Ant

I parte: la formica operosa che beve caffèdi

In questa serie di articoli verrà analizzato uno degli strumenti più efficaci per lo sviluppo e deploy di applicazioni enterprise. Lo scopo non è tanto quello di presentare il prodotto in ogni suo minimo dettaglio operativo e di configurazione, per i quali rimandiamo ai riferimenti, ma piuttosto dare una giustificazione del perché sia efficace utilizzare Ant nei vari contesti della programmazione Enterprise.

Perchà© Ant?

La storia recente ha messo in evidenza come, relativamente alla tecnologia Java, questo periodo storico possa essere considerato un momento di passaggio importante verso qualcosa di fortemente innovativo e proiettato in avanti.

Le nuove tecnologie rilasciate di recente hanno introdotto un livello di astrazione maggiore che permette non tanto di risolvere nuovi problemi, ma di risolvere problemi noti in modo nuovo e diverso, con una visione di più alto livello.

Tanto per capire la potenza di questo cambiamento, si può prendere ad esempio l‘approccio POJO oriented di EJB 3.0 (nata come formalizzazione di tecnologie già  utilizzate come Hibernate) dove di fatto spariscono l‘XML e tutta la complessità  connessa, o alla filosofia RAD di JSF (una vera e propria rivoluzione in ambito web application).

Questa rivoluzione sta portando forti cambiamenti anche nel mondo degli ambienti di sviluppo dove nasce una nuova famiglia di prodotti che traggono un grosso beneficio dalla adozione di questi nuovi strumenti di sviluppo visuali e che si stanno proponendo come lo step avanti rispetto ai ben noti IDE tipo JBuilder, o Eclipse.

Al momento in cui scrivo l‘articolo, i prodotti di riferimento che implementano in modo migliore le ultime novità  tecnologiche sono Oracle JDeveloper 10.1.3 e Netbeans 5.5; a ruota seguono i due prodotti etichettati ufficialmente da Sun, JStudio Creator e Sun Studio Enterprise, per i quali voci sparse indicano una prossima fusione con Netbeans a formare la futura piattaforma di sviluppo completa della casa californiana.

Il settore è quanto mai in agitazione tanto che, a rotazione una volta ogni quindici giorni circa, viene rilasciata una nuova versione di un prodotto concorrente al titolo di migliore ambiente di sviluppo.

Sulla base di questo nuovo scenario verrebbe da chiedersi se in tale fermento e con un livello tecnologico cosଠcomplesso abbia senso, al volgere dell‘anno del Signore 2006, parlare di uno strumento come Ant che potrebbe essere considerato il successore in chiave Java dei vecchi strumenti di compilazione usati per i linguaggi C/C++ e Unix a partire fin dagli anni Settanta.

La risposta è scontata ed è affermativa, sia perchà© intorno a noi un sempre maggior numero di programmatori nel mondo usa questo utilissimo strumento, sia perchà© Ant rappresenta la soluzione migliore a un problema ricorrente di questo momento: la piattaforma tecnologica è talmente complessa e in evoluzione che è impensabile basare il processo di sviluppo su un set prefissato e stabile di strumenti di sviluppo. Gli ambienti possono cambiare sia al variare delle versioni rilasciate che delle tecnologie da implementare; non è infrequente utilizzare un tool per lo sviluppo della parte web e uno per la parte EJB, affidando poi la riunificazione e il build finale a un qualche strumento open, indipendente dalla piattaforma, e che sia facilmente integrabile in ogni strumento di sviluppo.

Ant è tutto questo: è il "collante" che consente di amalgamare meglio lo sviluppo in team sotto il controllo di un qualche sistema di version control (come avremo modo di verificare in uno dei prossimi articoli di questa serie).

Nella interessante prefazione del libro "Ant: Definitive Guide" [ADG], James Duncan Davidson, il creatore della prima versione di Ant, racconta la sua esperienza verso la fine degli anni Novanta, quando lavorava in Sun nel team di sviluppo di Tomcat, dove si occupava fra le altre cose della certificazione cross-platform di quello che poi sarebbe divenuto il più popolare container web open source.

L‘autore descrive, in modo piuttosto pittoresco in alcuni passaggi, quel periodo passato a testare e ricompilare il container su tre piattaforme differenti (vincolo necessario per passare il programma di certificazione 100% Pure Java). Si tratta di un lavoro per certi versi piuttosto ripetitivo, e scarso di momenti eccitanti, se non si considera l‘interesse per la parte di ottimizzazione e automazione del processo di build e assemblaggio dei sottomoduli.

All‘epoca gli strumenti disponibili erano essenzialmente il Make Unix con i vari derivati fra cui lo GNU Make, oltre a qualche altro strumento diverso nella implementazione ma simile nella impostazione.

Questo strumento, oltre a mostrare una scarsa solidità  per la parte di configurazione (uno spazio inserito per errore accanto a un carattere tab provoca un errore di compilazione), difficilmente si adatta alla modalità  con cui si lavora in un progetto Java. Si pensi che, per la compilazione di ogni singola classe, il Make deve ogni volta mandare in esecuzione il compilatore con il file da compilare: si moltiplichi questo processo (costoso) per il numero di classi di Tomcat (o di un comune progetto enterprise mediamente complesso) e si otterrà  un tempo complessivo molto alto. Altra limitazione non di poco conto di un make non Java è che essendo un programma binario esterno alla JVM, non può interagire con quanto sta dentro il programma Java (le eccezioni ad esempio).

L‘autore sottolinea come fosse frustrante spendere la maggior parte del tempo nell‘osservare i log stampati durante la fase di compilazione e aggregazione. Mosso dalla necessità  di creare un prodotto utile e necessario al suo lavoro, più che dalla bramosia di realizzare un nuovo e rivoluzionario strumento di lavoro (almeno questo è quanto afferma nella succitata prefazione), l‘autore completò in poche ore l‘embrione di quello che poi sarebbe diventato uno degli strumenti più utilizzati al mondo.

Era il 1999, anno di nascita di Ant, il cui nome fu scelto per sottolineare la filosofa del progetto: "Ant, una piccola cosa che può fare grandi cose".

Inizialmente disponeva di due sole essenziali funzionalità  di base, la compilazione e la copia dei file: nonostante ciò l‘autore e i suoi colleghi trovarono utile utilizzare questo prodotto rudimentale tanto che il lavoro di certificazione di Tomcat subଠuna veloce accelerazione. Secondo Davidson i tempi di build si ridussero di un ordine di grandezza rispetto all‘utilizzo di GNU Make.

Grazie ai suggerimenti circa le modifiche necessarie proposte da un collega, anch‘egli in Sun, Davidson introdusse alcune importanti funzionalità  al prodotto, prima fra tutte la reflection e il formato XML per il file di build: in poco tempo Ant divenne quello che tutti noi conosciamo.

Il tool fu rilasciato in licenza open source e di pubblico dominio tramite control version system; nacque una comunità  di sviluppatori e il progetto fu inglobato nel progetto Jakarta.

L‘adozione della reflection permise di trasformare Ant da semplice esecutore di due operazioni motore estendibile in modo dinamico e trasparente. Ad oggi, alle due funzionalità  di Ant (in gergo target) che inizialmente erano cablate nel prodotto (copia e compilazione) si sono aggiunte una moltitudine di nuove funzioni create sia dal team di sviluppo che da programmatori sparsi in tutto il mondo.

E‘ l‘autore stesso che racconta (con un malcelato senso di soddisfazione e orgoglio) il totale sbigottimento quando, presso una conferenza mondiale su Java, notò come uno dei nuovi prodotti di sviluppo visuale presentato da una famosa casa di software, utilizzasse al suo interno Ant per le operazioni di compilazione e build.

Fu la consacrazione definitiva di una idea tanto semplice quanto efficace: la metafora della "formica" sembrava quanto mai appropriata.

Jump start installazione

Installare Ant è, come per tutti i prodotti del gruppo Jakarta (da Log4J a Tomcat) molto semplice: dopo aver scaricato dal sito del progetto Jakarta Ant [ANT] l‘archivio nel formato preferito, si può procedere alla scompattazione. Il tool funzionerà  quasi subito, dopo aver opportunamente impostato la variabile JAVA_HOME (che al solito deve puntare alla directory di installazione del JDK) e la ANT_HOME (che invece deve puntare alla directory dove si è scompattato l‘archivio di Ant).

Se tutte le operazioni sono state eseguite correttamente, si potrà  scrivere il seguente comando

ant -version

che restituire la versione del tool installato; nel mio caso:

Apache Ant version 1.6.5 compiled on June 2 2005

L‘installazione, come per ogni prodotto Jakarta "a linea di comando" non è intrusiva nella macchina e non dovrebbe modificare in alcun modo le impostazioni di sistema (come ad esempio il registry di Windows).

Per chi fosse interessato a "mettere le mani dentro Ant", sul buon manuale [ADG] potrà  scoprire come installare Ant eseguendo il build a partire dai sorgenti.

Per poter eseguire Ant, dopo aver opportunamente impostato il path di ambiente, si può invocare il comando "ant" di riga di comando passando come parametro il nome del file di build che si vuole utilizzare e il target da eseguire (per capire meglio questo passaggio, si veda la struttura e il significato del file di build).

Se non si specifica il build filename, verrà  cercato nella directory corrente un file con il nome usato convenzionalmente di default (build.xml).

Ecco un esempio di esecuzione di ant

ant -f  antbuild.xml init compile

in questo caso il comando esegue le istruzioni contenute nel file antbuild.xml relative ai target "init" e "compile".

Prima di passare alla struttura e significato di un ant build file, è bene fare una breve considerazione sulla filosofia adottata dal tool, filosofia che deve essere ben compresa anche dall‘utilizzatore.

Un qualsiasi target deve eseguire operazioni atomiche e sufficientemente semplici. Un target deve fallire non appena c‘è qualcosa che non va: ad esempio un build file che restituisca risultato positivo anche in presenza di un errore è un buildfile sbagliato. Gli errori che si verificano devono essere segnalati. Ci sono situazioni a margine in cui si possono ignorare i risultati dei controlli di checkstyle, ma si deve sempre poter essere in grado di verificare anche questa situazione. In generale si deve poter essere in grado di dire che "se un progetto ha passato Ant, allora va bene": per questo Ant non può essere di manica larga.

Ant deve eseguire le operazioni secondo un modello simile a quello che guida il processo di sviluppo del noto Rational Unified Process (RUP), sintetizzabile con la definizione pre-run-post: si parte da una serie di precondizioni che devono essere sempre vere (se la compilazione è andata bene, il target make-ejb-jar deve poter assumere che siano disponibili tutti i .class di progetto senza dover effettuare controlli), si esegue il target e si deve terminare con una postocondizione definita dal build file. Un target semplice come il compile o funziona, creando i compilati, oppure fallisce.

L‘atomicità  delle operazioni e la fedeltà  al modello pre-run-post è un requisito fondamentale: negli esempi molto spesso si trova la creazione di una directory nel target init, mentre è preferibile eseguire questa operazione all‘interno del target che ha bisogno di tale directory. In tal modo è più chiaro l‘evolversi delle operazioni quando "si pulisce il sistema".

Struttura di un file di build

Come si è avuto modo di preannunciare brevemente, per eseguire una qualsiasi serie di operazioni, è necessario inserire la definizione delle singole operazioni in un file di build XML.

In questo file è possibile inserire un numero arbitrario di operazioni che sono identificate tramite appositi target: dall‘esterno a linea di comando sarà  quindi possibile scegliere quale target eseguire semplicemente specificandone il nome.

I target sono atomici, anche se è possibile definire delle relazioni di interdipendenza: ad esempio si può specificare di eseguire il target compile successivamente ai target di inizializzazione e di clean del progetto. Un target che specifica delle dipendenze, verrà  eseguito solo se i target dipendenti sono eseguiti con successo.


Figura 1 - Organizzazione macroscopica del file Ant.

Ant gestisce automaticamente queste dipendenze, controllando la validità  complessiva sia delle definizioni che del risultato delle esecuzioni. Ant esegue controlli anche al fine di eliminare cicli, annidamenti ricorsivi incrociati e casi che possono portare al blocco del processo di build.

Generalmente un build file corrisponde a un progetto, ma sono possibili diverse configurazioni in modo da comporre le varie opzioni o caricare gruppi di proprietà  da file esterni.

Il file di build è in formato XML, per il quale non è stata specificata la struttura DTD e sul quale Ant esegue solamente un controllo formale.

Un file di build XML è strutturato in modo da includere le definizioni dei seguenti elementi.

  • Project

E‘ il target radice e serve per specificare gli attributi di base del progetto Ant, come il nome, la directory base e il target di default (che verrà  eseguito se non si specifica nessun target da riga di comando).


Figura 2 - Il tag project.

  • Targets

Si tratta di una serie di blocchi XML ognuno dei quali permette di eseguire una o più operazioni e sono i comandi che si possono eseguire dall‘esterno. Ogni target deve essere considerato come una unità  eseguibile di operazioni e contiene al suo interno le istruzioni di configurazione oltre a un task di esecuzione.

Ant dispone di alcuni template di esecuzione già  configurati, come ad esempio il "javac" che permette di compilare, il "java" che consente di eseguire una classe, o il "sql" con il quale si possono eseguire operazioni di setup sul DB. Molto utilizzati anche i task per la creazione dei file di deploy (task "jar" e "manifest").

Di seguito un esempio di un target molto comune, che permette di compilare i sorgenti della applicazione copiandoli all‘interno della directory classes.

Il target fa uso del task "javac"

    
    
    
        destdir="${classes.dir}"
        debug="on"
        deprecation="on"
        optimize="off">
        
            
                
            
        
            
    

Si noti l‘uso delle proprietà  identificate tramite la sequenza di caratteri ${nome_variabile}: usualmente dentro il file di build si trova una sezione, o meglio un target in cui vengono configurate tutte le proprietà  necessarie ai target successivi.

Ad esempio può essere utile inserire un target come il seguente:

    
    
    
    
    
    
    
...

Si ricordi che l‘ordine di definizione dei target, delle variabili è importante e che il file segue una sintassi case sensitive.

Conclusione

Per motivi di spazio non è possibile elencare nei minimi dettagli ogni elemento di un build file e quindi si rimanda alla documentazione ufficiale per la spiegazione completa. Nelle prossime puntate vedremo in alcune tecniche utili in contesti specifici, come le web application, le applicazioni EJB e i test di unità ; presenteremo anche un file di Ant molto utile per lavorare in progetti JavaEE.

Riferimenti

[ANT] Sito ufficiale del progetto Jakarta Ant, http://jakarta.apache.org/ant

[ADG] Jessy Tilly - Eric Burke, "Ant Definitive Guide", Ed. O‘Reilly.

Condividi

Pubblicato nel numero
112 novembre 2006
Giovanni Puliti lavora come consulente nel settore dell’IT da oltre 20 anni. Nel 1996, insieme ad altri collaboratori crea MokaByte, la prima rivista italiana web dedicata a Java. Da allora ha svolto attività di formazione e consulenza su tecnologie JavaEE. Autore di numerosi articoli pubblicate sia su MokaByte.it che su…
Articoli nella stessa serie