MokaByte Numero  40  - Aprile 2000
 
MiniPad
Come progettare e
implementare un editor Java 
con compilatore in linea
di 
Andrea Gini
Parte I: Use Case e Diagramma di Specifica

Alcuni mesi fa, poco prima dell'estate, decisi che era giunto il momento di approfondire la mia conoscenza del linguaggio Java. Dopo aver scaricato l'ultima release del JDK mi misi in cerca di un piccolo editor per sviluppare i miei programmi. Rimasi sorpreso nello scoprire un'infinita' di programmi capaci di una quantita' straordinaria di funzioni sofisticate (tipo: traduzione simultanea in greco antico, cifratura in chiave pubblica-privata, consultazione on-line della Treccani....) quando quello di cui avevo bisogno era solo un piccolo editor con il compilatore in linea. 
Pensai cosi' di svilupparne uno in proprio (che in un impeto naive decisi di chiamare JiniPad giocando a combinare Java con il mio cognome).

Introduzione
Nel corso dei mesi estivi ho sviluppato il progetto in modo da aggiungere nuove importanti funzioni (gestione di piu' di un documento, supporto esteso al C, configurabilita', utilizzo delle Swing ecc) fino ad arrivare a quel momento cruciale in cui un software collassa per le troppe modifiche. Era giunta l'ora, mi accorsi mio malgrado, di gettare tutto alle ortiche e di ricominciare da capo.
 

Questa operazione, nota in letteratura come reengineering, consiste nel costruire qualcosa di nuovo che svolga la stessa funzione di qualcosa di esistente ma che lo faccia in maniera radicalmente diversa. L'esperienza accumulata nello sviluppo del prototipo e' decisiva per definire le basi del nuovo progetto.

Prima di gettarmi in questa nuova impresa pero' ho voluto intraprendere lo studio dell'Ingegneria del Software, ed e' cosi' che sono venuto a conoscienza dell'Unified Modeling Language, noto anche con l'acronimo UML.

Con questo articolo voglio proporre un'esperienza di progettazione Object Oriented riprendendo in mano l'idea iniziale di costruire un semplice editor, ricorrendo fin dal principio al supporto dell'UML. 

Allo scopo di rendere questo articolo utile ad un pubblico quanto piu' vasto possibile, non faro' nessuna assunzione su conoscenze preesistenti di UML, e cerchero' di produrre codice java commentato e di facile comprensione.
 
 
 

Prologo: preparazione dell'ambiente di lavoro
Oltre all'indispensabile JDK1.2 (o superiore), tengo sempre con me la documentazione ufficiale e i sorgenti delle API (potete trovarli nel file src.jar nella root del jdk dopo averlo scompattato con WinZip)
Infine occorre un modeler UML: il Rational Rose Student Edition (www.rational.com/rose sezione download) e' gratuito e va benissimo per cominciare. 
 
 

UML in poche parole
UML e' una notazione grafica utile nel processo di progettazione Object Oriented. Utilizzando i diagrammi UML (ne esistono sette tipi, ma in questo caso ne usero' solo tre) si possono modellare i diversi aspetti di un sistema software.
Un primo enorme vantaggio di tale notazione e' che dona  una sorta di "esistenza materiale" al software, permettendo di gestirne meglio la fase di progettazione e di manutenzione.
Si possono realizzare diagrammi UML con l'ausilio di appositi tool di sviluppo (simili  a programmi di disegno) che eseguono anche un certo controllo semantico.
Il piu' famoso di questi tool e' Rational Rose.
 
 
 

Iniziamo i lavori: definiamo il problema
Vorrei un programma che mi permetta di editare un sorgente Java (alla maniera del Wordpad), salvarlo, compilarlo ed eseguirlo con la semplice pressione di un pulsante. Vorrei anche vedere l'output del compilatore su una  finestra separata da quella dell'editor.
La richiesta e' molto vaga, ma corrisponde a quanto un ipotetico committente potrebbe richiedere. Per prima cosa provo a costruirne un modello con uno Use Case Diagram.
 
 

L'omino e' un Attore, i palloni sono Use Case, mentre le frecce mostrano una connessione tra i primi e i secondi o tra uno Use Case ed un'altro.
Il nostro utente puo' creare un nuovo documento, aprirne uno esistente, salvare quello corrente, editarlo, compilarlo e farlo partire. Alcune di queste azioni hanno come conseguenza l'avvio di un altro Use Case.
Questo diagramma fornisce una visione ad altissimo livello del progetto: ho definito cosa fa il programma, ma non ho fatto ancora nessuna assunzione sul come. Persino un programma complesso come Photoshop puo' essere ridotto ad una famiglia di diagrammi simili a questo, senza scendere nel dettaglio.
Con un diagramma di questo tipo posso esporre la mia visione del sistema ad un ipotetico committente, e assicurarmi di aver capito cosa mi e' stato richiesto. Durante una colazione con amici ho riscontrato come un paio di questi semplici disegnetti sia di per se sufficiente per provocare un interessante brainstorming.
 
 
 

Cerchiamo un po' di aiuto
Prima di cominciare a lavorare si puo' cercare qualche scorciatoia, tipo una API o una libreria che aiuti a risolvere una parte del problema. Il componente JTextArea del package javax.Swing svolge "gratis" tutte le funzioni di editing che servono in questa occasione, e pertanto lo includo fin dal principio nel progetto.Possiamo dedicarci allo sviluppo del progetto da un livello piu' alto, senza la preoccupazione di gestire l'editing di testo a basso livello (un problema niente affatto banale!)
 
 
 

Il dominio applicativo: definizione delle prime classi
Un'analisi dell'enunciato puo' essere di aiuto nello scovare le classi del Dominio Applicativo, vale a dire gli oggetti "del mondo reale" con cui il nostro programma dovra' interagire. L'unica cosa che so per ora e' che devo trattare i seguenti oggetti:
- Un sorgente Java (un file *.java)
- Un Compilatore (javac)
- Una JVM (java)
ognuno dei quali racchiude il comprtamento di un qualcosa di preesistente. Per modellare in UML queste classi posso ricorrere ai Diagrammi di Classe
 


I tre rettangoli qui sopra sono caratterizzati da un nome (in alto) da attributi (in mezzo) e da operazioni (in basso). Accanto ad ogni attributo c'e' un lucchetto che li caratterizza come privati. Il simbolo accanto alle operazioni le denota come pubbliche.
Di Javac e di JVM so per certo che dovranno, rispettivamente, compilare ed eseguire un sorgente java. 
Il JavaDocument racchiude il testo di un sorgente (attributo source), il File in cui verra' salvato, il nome della classe e quello del sorgente. Come operazioni definisco insertString() e remove() per agire sul testo, getFile() e setFile() per richiedere o modificare il file di destinazione, getClassName() e getSourceName() per chiedere il nome del sorgente e della classe.
Le frecce tratteggiate indicano che le classi Javac e JVM eseguono operazioni sulla classe JavaDocument (si puo', ad esempio, immaginare che Javac chieda al JavaDocument il nome del file da compilare).
 
 
 

Alcune classi di supporto
Il seguente diagramma ne fornisce una vista molto stilizzata del componente JTextArea.

C'e' una classe Document che racchiude un testo (inteso come una "collezione di caratteri"). La classe JTextArea fornisce una vista grafica sul Document di sua proprieta' (il possesso e' simboleggiato dalla freccia solida). Le operazioni cut(), copy() e paste() provocheranno un cambiamento nel Document attraverso una opportuna combinazione di  insertString() e remove().
La classe EditorKit contiene alcune operazioni utili a maneggiare il documento. A me interessano solo read() e write() che permettono di caricare un file da disco e di salvare il documento corrente.
Mi serve anche un oggetto Console che mostri all'utente l'output del compilatore. Senza scendere nei dettagli la rappresento cosi'
 

Per tenere insieme il sistema e fornire un interfaccia utente creo una classe MiniPad



Mettiamo tutto insieme
A questo punto posso provare a mettere tutto assieme e a vedere cosa emerge
 

  

C'e' una classe MiniPad che fornisce all'utente di le operazioni newDocument(), openDocument(), save(), saveAs(), exit(), compile(), runProgram() e stopProgram(); una classe Console che permette all'utente di vedere l'output del compilatore (non sappiamo ancora come), una classe JTextArea che da' modo all'utente di leggere e scrivere il JavaDocument.
Seguendo le frecce si puo' anche immaginare come avviene la comunicazione tra i componenti: ad esempio se l'utente chiama il metodo compile() il MiniPad eseguira' le seguenti operazioni (in pseudo-java):
 

JavaDocument doc = JTextArea.getDocument();
Javac.compile(doc);


Di conseguenza il Javac chiamera' il metodo bindOutput() sull'oggetto Console.
In verita' questo diagramma e' ancora distante dall'implementazione (anche se sotto certi aspetti la suggerisce) poiche' non fornisce un grado di dettaglio adeguato.
In compenso e' semplice e chiaro, e potete provare ad illustrarlo a vostra madre avendo una buona probabilita' di farle capire cosa intendete fare (il discorso non vale se vostra madre e' Ingegnere Nucleare!)
Martin Fowler (autore di UML Distilled) definisce diagramma di classe con questo livello di dettaglio Diagramma di Specifica.
Il mese prossimo procedero' verso un Diagramma di Classe Implementativo. 
Quindi procedero' a creare il modello di comunicazione tra oggetti usando i Diagrammi di Sequenza. E per finire presentero' una implementazione completa e funzionante di questo progetto.
 
 
 

Bibliografia e Letture Consigliate

"UML Distilled" second edition   Martin Fowler      ADDISON-WESLEY

"Open Sources Voices from the Open Source Revolution"     Edited by Chris DiBona, Sam Ockman & Mark Stone    O'Reilly

"Tutto Sherlock Holmes"     Arthur Conan Doyle     Newton Compton Edition
    disponibili anche su http://members.tripod.com/~msherman/holmes.html

 

Chi volesse mettersi in contatto con la redazione può farlo scrivendo a mokainfo@mokabyte.it