MokaByte Numero 33  -  Settembre  99 
Waba
Un mini-Java  per palmari
di 
Michele
Sciabarrà
Vediamo  come sia possibile programmare un embedded device utilizzando un Java non convenzionale


Esaminiamo Waba, un piccolo linguaggio portabile simile a Java, progettato per essere utilizzato sui sistemi palmari basati su PalmOS e Windows CE, rispettando le notevoli restrizioni di memoria di questi sistemi

I computer palmari sono una realtà di mercato in rapida crescita che fanno seguito al successo delle agendine elettroniche. Il computer nel palmo di una mano mostra ogni giorno sempre di più la sua utilità. Una software house che intenda essere innovativa e preparata al futuro non può ignorarli. Vediamo dunque come sviluppare per i sistemi palmari attualmente più diffusi sul mercato, ovvero i palmari basati sul PalmOS di 3Com, e quelli basati sul Windows CE di Microsoft. Il nostro intento originario, che ha motivato questo articolo, era quello di esaminare la possibilità di scrivere programmi per palmari utilizzando Java come linguaggio, possibilmente ottenendo applicativi utilizzabili su entrambi sistemi.I palmari sono caratterizzati dall'esiguità delle risorse disponibili. Per esempio i Palm Pilot hanno in media 2 megabyte di RAM, mentre i sistemi CE ne hanno in media 4. Occorre notare che, poiché i palmari NON hanno hard disk, la memoria serve per contenere sia il programmi che i dati. In pratica un programma non può ragionevolmente occupare più di 100, 200k.Per venire incontro alle restrizioni dei piccoli sistemi, Sun ha sviluppato le specifiche PersonalJava ed EmbeddedJava. Sfortunatamente al meglio delle mie conoscenze nel momento in cui scrivo questo articolo (maggio 1998), non sono disponibili implementazioni che consentano di scrivere applicazioni in Java per WinCE e PalmOS. Piuttosto PersonalJava ed EmbeddedJava sembrano destinate al mercato dei RTOS (Real Time Operating System) in cui dominano sistemi operativi realtime (spesso proprietari) come il VxWorks o il QNX.Ero dunque rassegnato a scrivere le mie applicazioni per palmari in C, con la consapevolezza di dover affrontare la ripida curva di apprendimento delle API di PalmOS e WinCE, e la susseguente necessità di dover scrivere due versioni completamente diverse di un applicativo, quando mi sono imbattuto in Waba. Il Waba era proprio il "Java per palmari" (Java comunque in senso lato) che stavo cercando. La cosa più interessante è che Waba è distribuito gratuitamente. Ho contattato per email l'autore, Rick Wild, il quale mi ha detto che tale package (WabaVM e WabasSDK) rimarranno distribuiti gratuitamente (anche se non in sorgente - per quelli occorre pagare). Notare infine che i programmi sono in ancora in beta, ma nell'uso pratico non ho incontrato il benché minimo problema. Non posso però dire di avere fatto applicazioni molto complesse.
 
 
 
 

Cos'è Waba

Waba permette effettivamente di scrivere applicazioni per palmari utilizzando Java come linguaggio di programmazione. L'applicazione ottenuta può girare su PalmOS e Windows CE, e anche come applet Web. Nel valutare Waba bisogna però tenere presente che Java non è solo un linguaggio ma una completa piattaforma per lo sviluppo di applicazioni, che comprende una virtual machine e una vasta libreria di classi. Un programma Java vero e proprio deve essere fatto di bytecode in grado di girare su una Java Virtual Machine standard, utilizzando la libreria di classi standard. Questo non è vero per Waba in quanto usa un sottoinsieme del linguaggio Java, genera un suo formato proprietario di bytecode ed utilizza una sua virtual machine, la WabaVM, che comprende anche una (piccola) libreria di classi specifica di Waba. Quindi Waba non può in alcun modo essere definito un ambiente di sviluppo compatibile con la piattaforma Java di Sun. Dico questo a scanso di equivoci, perché Sun (e non solo) è molto sensibile alla "purezza" di Java, vedi le recenti cause fatte alla Microsoft.Ciò nonostante, la rinuncia al pieno supporto di Java comporta dei notevoli vantaggi in "leggerezza": la WabaVM (librerie di classi comprese!) su un PalmPilot occupa solo 69K, mentre sui WindowsCE circa un centinaio di kilobyte. Considerando che il solo classes.zip di Java 1.1 occupa 6 megabyte, si ottiene un bel vantaggio in compattezza. Ovviamente la libreria di classi di Waba consente di fare molto meno rispetto di quello che può essere fatto con la libreria di Java completa.Per scrivere un programma in Waba si deve avere a disposizione un kit di sviluppo Java, per esempio il JDK di Sun. Occorre però scrivere il programma utilizzando solo un sotto-insieme del linguaggio Java, e precisamente:
  • Non si possono usare long e double
  • Non si possono utilizzare eccezioni
  • Non si possono utilizzare funzioni legate ai thread (sincronizzazioni eccetera)
  • Si deve utilizzare soltanto la libreria di Waba.
Waba è fornito di una libreria di classi che permette la compilazione e l'esecuzione di programmi Waba in uno specifico ambiente Java ospite, in particolare il browser Netscape Navigator. Un programma Waba è dunque un normale programma in Java che può essere compilato ed eseguito utilizzando la libreria di classi Waba. Infatti l'ambiente di test di Waba è un nomale browser Java-enabled che permette di eseguire il programma come applet.Una applicazione Waba può essere scritto e testato utilizzando gli strumenti forniti da un ambiente di sviluppo Java per applet. Per trasformare in un programma per la JVM in un formato eseguibile dalla WabaVM occorre usare il programma warp che trasforma un insieme di classi in un unico file con l'estensione .wrp in grado di essere eseguito dalla WabaVM. In pratica il programma warp trasforma il bytecode della JVM in un bytecode adatto alla WabaVM, e mette insieme le classi in un unico file. Il file.wrp può essere eseguito direttamente sui sistemi WindowsCE, mentre per i sistemi PalmOS è necessario un passo ulteriore: occorre usare il comando exegen che genera un eseguibile (.prc) e un database (.pdb) per il PalmOS. Dopo di che basta installare i programmi sul palmare e mandarli in esecuzione.
 
 
 
 

Hello World

Vediamo con maggior dovizia di particolari le fasi sopra descritte vedendo passo passo come scrivere il classico programma HelloWorld. Innanzitutto procuriamoci la libreria di Waba, compresa nel WabaSDK scaricato da www.wabasoft.com. Il kit comprende la versione Java delle classi Waba. Creiamo dunque un progetto utilizzando per con il nostro ambiente di lavoro preferito. Nel mio caso mi sono limitato ad utilizzare il JDK e il notepad per lo sviluppo dell'applicazione. Per applicazioni un po' più complesse un IDE vero e un debugger migliore del JDB sono sicuramente più appropriati. Il testo del programmino è semplicemente questo:
 
import waba.ui.*;
import waba.fx.*;
public class Hello extends MainWindow{
  public void onPaint(Graphics g){
    g.setColor(0, 0, 0);
    g.drawText("Hello World", 0, 0);
  }
}
In dettaglio: abbiamo importato il package waba.ui per usare la classe MainWindow, e il package waba.fx per usare il contesto grafico Graphics. La classe principale di un programma Waba deve essere derivata da waba.ui.MainWindow , come le applet devono essere derivate da java.applet.Applet. Sempre in analogia alle applet, che richiedono la ridefinizione del metodo paint, per disegnare in Waba occorre ridefinire il metodo onPaint. La libreria di Waba segue la convenzione che i metodi chiamati onXxx devono essere ridefiniti, mentre gli altri metodi possono essere chiamati. Quindi per scrivere Hello World dobbiamo soltanto ridefinire onPaint e disegnare utilizzando il contesto grafico Graphics. In molti casi le classi di Waba hanno nomi e metodi simili a classi omonime di Java. Il Graphics rappresenta l'area di disegno, che è come una bitmap fornita dal sistema dove possiamo disegnare; una volta che abbiamo svolto il nostro lavoro è compito del sistema visualizzare quanto disegnato. Preparato il nostro sorgente, possiamo compilare la nostra applicazione usando il JDK, con un comando come:
C:\waba\disk> javac -classpath waba10b7.jar Hello.java
Notare che abbiamo usato solo le librerie di Waba (specificandole con -classpath) per compilare, così se per errore inseriamo nel sorgente qualche elemento non incluso nella libreria di Waba, saremo avvertiti da un errore di compilazione. Una volta compilata la classe Hello.class, questa può essere mandata in esecuzione come applet utilizzando una pagina HTML come quella che segue: 
 
<applet code=waba.applet.Applet 
archive=waba10b7.jar 
width=160 height=160>
<param name=appClass value="Hello">
</applet>


Abbiamo quindi incluso l'archivio delle classi waba, specificando come applet la classe waba.applet.Applet. Poiché la classe Hello non è derivata da java.applet.Applet non può essere usata come applet, per cui la classe effettiva da caricare viene specificata dal parametro appClass
 
Figura 1

In figura 1 possiamo vedere il risultato con Netscape. Noterete che finora non c'è niente di speciale. La parte interessante viene ora. Eseguendo 
 

C:\waba\disk> warp c /q Hello Hello.class


viene trasformata la classe Hello.class in Hello.wrp e creato un link Hello.lnk necessario per lanciare l'applicazione in esecuzione su Windows CE. Adesso possiamo caricare il programma su un palmare WindowsCE; i passi da eseguire sono:

  • aprire l'H/PC explorer di Window CE, 
  • installare la WabaVM per Windows CE in \Program Files (copiare con un drag and drop)
  • installare l'Hello.wrp sempre in \Program Files
  • copiare il link sul desktop (o dove lo ritenete opportuno)
  • cliccare sul link sul desktop
Viene mandata così mandata in esecuzione la WabaVM, usando come argomento il file del programma Waba sviluppato; e in Figura 2 potete vedere il risultato. 
 
 
Figura  2

 
 

Adesso passiamo al PalmOS. Per generare un programma per PalmPilot occorre usare l'Hello.wrp appena generato, e trasformarlo in una coppia di file (Hello.prc e Hello.pdb) eseguendo:

C:\waba\disk> exegen /q /w 160 /h 160 /i satori.bmp Hello Hello Hello

I parametri specificano la dimensione del display e la bitmap che rappresenta l'icona del programma. I passi per mandare il programma in esecuzione sono:

  • Installare la Waba VM: doppio click su waba.prc e waba.pdb
  • Installare l'applicazione: doppio click su hello.prc e hello.pdb
  • Eseguire HotSync per sincronizzare il Palmare con il computer
  • Lanciare Hello dal menù principale
Il programma viene così lanciato e in Figura 3 potete vedere il risultato in esecuzione.Notare che i passi di installazione della WabaVM devono essere eseguiti una volta sola, in quanto una sola WabaVM è sufficiente per l'esecuzione di diversi programmi.
 
 
Figura 3

 
 
 

La libreria di Waba

La libreria di Java è composta, al momento in cui scrivo (Waba 1.0 beta7) da sole 37 classi suddivise in 6 package. Molte classi sono modellate su omonime classi del JDK e nella maggior parte dei casi rappresentano sostanzialmente un subset dei loro "fratelli maggiori". Come si può intuire la dotazione è ridotta allo stretto necessario. Tanto per fare un esempio abbiamo un waba.util.Vector ma non una Hashtable. I package forniti con Waba sono:
 
waba.fx
waba.ui
waba.io
waba.lang
waba.sys
waba.util


Il package waba.fx fornisce il framework grafico di base, ovvero le classi necessarie per disegnare testo e grafica: contesto grafico (Graphics), font (Font e FontMetrics), rettangoli (Rect) e immagini (Image). Questo framework è usato per costruire i componenti di interfaccia utente, disponibili nel package waba.ui. La dotazione di compontenti GUI non è eccelsa ma nemmeno poverissima: abbiamo i consueti bottoni, label, radio button e checkbox, i campi di testo e le tab bar utilizzate per costruire dialoghi simili a quelli tabbed di Windows. Oserei dire che questi ultimi sono quasi essenziali date le limitazioni del display. Sempre per quanto riguarda l'interfaccia, in Java AWT abbiamo Component e Container, mentre in Waba abbiamo Control e Container che svolgono le stesse funzioni. È importante notare che i Container come in Java possono contenere altri componenti di interfaccia, ma a differenza di Java, in Waba non sono supportati i LayoutManager. Quando un Control viene inserito in un container si devono anche specificare le coordinate assolute del componente. Un altro aspetto importante è l'input-output gestito dal package waba.io. Sui palmari l'unità di I/O generalmente non è il file ma il database, ovvero una collezione di record ad accesso diretto: infatti i palmari hanno solo RAM e quindi non ha senso imporre la lettura sequenziale di un file quando è possibile senza problemi l'accesso diretto. Quindi si usano principalmente i database, che in Waba sono chiamati Catalog. Per la verità un Catalog assomiglia abbastanza ad un file di testo, dove i record sono simili a linee di testo (ovvero sequenze di byte a lunghezza variabile) con i metodi che consentono di andare avanti e indietro tra questi record, e di leggerli o scriverli. Nulla di più. Waba ha anche una classe File che rappresenta un file, ma non è utilizzabile sul PalmOS (che non ha niente del genere) ma solo con Windows CE. Altre classi di I/O supportate sono rappresentate da SerialPort, che consente l'accesso alla porta seriale (presente in tutti i palmari), e da Socket che consente di stabilire connessioni di rete quando il palmare è collegato ad Internet o ad una Intranet TCP/IP.Oltre a quanto detto finora rimane poco altro. In waba.util abbiamo solo il Vector di cui abbiamo già detto. In waba.lang abbiamo l'Object che ha il solo metodo toString(), e due classi per gestire stringhe: la String e la StringBuffer. Infine in waba.sys abbiamo una classe Convert per le conversioni di tipi, la classe Time per gestire data e ora, ed infine la classe Vm che raccoglie svariati metodi vari come copyArray() o getPlatform() che possono essere considerati "di sistema".
 
 
 
 

Un esempio più complesso

Realizziamo adesso un esempio meno banale, ovvero un convertitore da Lire in Euro e viceversa. L'intero listato è visibile nel listato che segue. 
import waba.ui.*;
import waba.fx.*;
import waba.sys.*;

class EuroCvt extends Container 
{

Label lfrom;
Label lto;
Edit from;
Label to;
Button cvt;
float kcvt;
 

EuroCvt(String sfrom, String sto, float k) 
{

kcvt = k;
lfrom= new Label(sfrom, Label.RIGHT);
lfrom.setRect(5, 0, 40, 18);
add(lfrom);

from = new Edit();
from.setText("0");
from.setRect(55, 0, 60, 18);
add(from);
 

lto= new Label(sto, Label.RIGHT);
lto.setRect(5, 20, 40, 18);
add(lto);

to = new Label("0");
to.setRect(57, 20, 60, 18);
add(to);

cvt = new Button("Converti");
cvt.setRect(40, 40, 60, 18);
add(cvt);
 

Label tmp = new Label("written by Michele Sciabarra'");
tmp.setRect(2, 60, 60, 18);
add(tmp);
tmp = new Label("(c) 1999 SATORI Network Solutions");
tmp.setRect(2, 80, 60, 18);
add(tmp);
//tmp = new Label("k = "+Convert.toString(kcvt));
//tmp.setRect(2, 100, 60, 18);
//add(tmp);
 

}

public void onEvent(Event event)
{
if (event.type == ControlEvent.PRESSED && event.target==cvt)
{
float f = Convert.toInt(from.getText()) * kcvt;
String s  = Convert.toString((int)(f*100));
int l = s.length();
to.setText(s.substring(0, l-2).concat(".").concat(s.substring(l-2,l)));
}

}
}

public class Euro extends MainWindow
{
TabBar bar;
Tab euro;
Tab lit;
EuroCvt lit2euro;
EuroCvt euro2lit;
 

public Euro()
{
TabBar bar = new TabBar();
lit = new Tab("Lit");
bar.add(lit);
euro = new Tab("Euro");
bar.add(euro);

bar.setRect(0, 0, this.width, 20);
add(bar);

float k = (float)1937.26;
lit2euro = new EuroCvt("Lit", "Euro", 1/k);
lit2euro.setRect(0, 30, this.width, this.height - 30);
euro2lit = new EuroCvt("Euro", "Lit", k);
euro2lit.setRect(0, 30, this.width, this.height - 30);

add(lit2euro);
}

public void onPaint(Graphics g)
{
g.setColor(0, 0, 0);
g.drawLine(160, 0, 160, 160);
g.drawLine(0, 160, 160, 160);
}
 

public void onEvent(Event event)
{

if (event.type == ControlEvent.PRESSED)
{
if (event.target == lit)
{
remove(euro2lit);
add(lit2euro);
}
else if (event.target == euro)
{
remove(lit2euro);
add(euro2lit);
}
}
}
}

Abbiamo due classi, la classe principale Euro che estende MainWindow , e una classe EuroCvt. La classe principale è un contenitore, che comprende una tab bar e l'area di lavoro della seconda classe. La seconda classe è un generico convertitore da x a y in base ad una costante k.A secondo di quale tab si seleziona sceglie appare uno dei due convertitori, ovvero una istanza di EuroCvt inizializzata con opportuni parametri, in modo da convertire da Lire in Euro o viceversa. Nel costruttore, Euro non fa altro che creare due istanze di EuroCvt, e gestire gli eventi di selezione del pannello. Notare attentamente nel listato che ogni elemento di interfaccia viene creato e aggiunto al suo container, ma che la sua posizione viene determinata in coordinate assolute utilizzando setRect(). La gestione di eventi di Euro (metodo onEvent) semplicemente visualizza l'EuroCvt che converte da lire ad euro oppure quella da euro a lire (metodi add e remove del Container). La classe EuroCvt è quella che fa la maggior parte del lavoro. Il costruttore è parametrico in modo da poter specificare i nomi delle valute sorgente e destinazione, compresa una costante moltiplicativa che permette di convertire una valuta nell'altra. Il costruttore definisce e posiziona tutti gli elementi di interfaccia mentre la gestione eventi raccoglie solo la pressione del tasto "Converti" ed effettua la conversione. Notare come l'arrotondamento a due cifre, per carenza di funzioni matematiche adeguate, viene fatto utilizzando la gestione di stringhe.
 
 
 
 

Conclusioni

Java ha attirato da tempo l'attenzione degli sviluppatori di applicazioni per sistemi embedded, dove ancora domina il C, e il C++ si rivela talvolta inadeguato. L'implementazione JDK di Java non è assolutamente pensata per l'uso real-time o in ambienti con stringenti requisiti di memoria, tutt'altro. Ciò nonostante la somiglianza con C e C++ e la semplicità unita alla potenza del linguaggio hanno fatto nascere un movimento di interesse intorno alle prospettive di uso di Java in questi ambiti. Non esiste solo Waba: ci sono numerose altre soluzioni come compilatori nativi o implementazioni real-time di Java (il Perc per esempio). Recentemente Sun e altri hanno costituito un Jconsortium proprio per studiare e standardizzare il Java real-time. Non dimentichiamoci che la prima applicazione di Java è stato proprio un sistema embedded (un telecomando intelligente), che Motorola (e altri) hanno preso in licenza la tecnologia Java, e dunque la prospettiva di avere il Duke nel nostro prossimo telefono cellulare è tutt'altro che campata in aria.
 
 
 
 

Bibliografia

 
Michele Sciabarrà, laureato in Scienze dell'Informazione, è direttore tecnico di SATORI Network Solutions, ditta marchigiana focalizzata su Java, Linux e PalmOS. Programma in svariati linguaggi da 15 anni, e in Java da quando il linguaggio era in versione alpha. È stato tra gli espositori di applicazioni Java già alla 1st Italian Java Conference, ha scritto decine di articoli su Java, sviluppato numerose applicazioni in Java . È stato docente di Java per importanti clienti tra cui IBM, Cariplo, Siemens-Nixdorf. Mantiene sul Web un corso online di linguaggio Java (http://www.satorins.com/CorsoJava)

  
 

MokaByte rivista web su Java

MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it