LA NUOVA VERSIONE 1.1 DEL JAVA E I TOOL DI SVILUPPO

Ormai Java e' in circolazione da più di un anno, e le cose sono molto cambiate rispetto ai primi mesi, dove l'unico tool di sviluppo disponibile era il Java Developer Kit 1.02 (JDK) della Sun.
Nei primi mesi del 1996 i pionieri del Java, tra i quali posso citare anche me stesso, sviluppavano semplici applet scrivendo il listato con un normale editor di testi, e salvato il .java lo compilavano da shell dos con il lento JDK, per poi verificare il risultato con l'ancora più lento appletviewer. Poi le cose sono migliorate con l'uscita dei primi JIT (Just in Time compiler), che velocizzano di molto l'esecuzione delle applet Java: si compilava sempre con il JDK, ma se non altro con l'Explorer e il Netscape, dalla terza versione in avanti, si potevano testare le applet godendo di una velocità molto superiore a quella dell'appletviewer Sun.
Nel frattempo era uscito anche il Symantec Cafè, il primo vero tool completo, con un proprio JIT, ed un ambiente integrato dove il passaggio tra editing, debugging e testing si è molto velocizzato.
Oggigiorno le offerte di tool ed altri accessori per Java, tra sistemi di sviluppo di grandi case come Microsoft, Borland e Asymetrix e utilità o collezioni di componenti, offerti da società minori o da singoli programmatori su Internet, è divenuta quasi comparabile a quella di linguaggi molto più vecchi ed affermati come il C++.
Recentemente è uscito il JDK 1.1, che sarà supportato dai browser come Netscape 4 e dalle prossime versioni dei tool di sviluppo; attualmente però conviene sempre usare la versione 1.02, dato che e' quella supportata dai browser attuali, e anche dai nuovi browser per compatibilità verso il basso.
A parte il caso delle intranet, dove si può accertare l'assenza di utenti che usano browser con JVM (Java Virtual Machine) 1.02, per internet si dovrà attendere la quasi totale sparizione dei vecchi browser, o più semplicemente si vedranno comparire dei menù di scelta nei vari siti, per selezionare le pagine per Netscape/Explorer versione 3, oppure 4 e superiori.


Il Java come sostituto del C++

Le grandi applicazioni commerciali sono attualmente scritte in C++, ma l'annuncio che molti tool di sviluppo potranno compilare opzionalmente in codice nativo, ad esempio Intel x86 per Windows, porta sempre più a pensare che il Java sarà adottato in molti casi al posto del C++.
I vantaggi di Java sono soprattutto la mancanza di puntatori, causa di complessità eccessive e bug, e la gestione automatica dell'allocazione della memoria (Garbage Collection), che rende molto più veloce e sicuro lo sviluppo.
Personalmente non credo che il Java sostituirà mai completamente il C++, dato che quest'ultimo avrà sempre maggiore controllo diretto sulle specifiche caratteristiche della piattaforma e maggiori prestazioni; comunque se il Java riuscirà effettivamente ad aggiudicarsi il mercato del "multiplatform" con il suo formato bytecode, è evidente che sempre più spesso gli sviluppatori decideranno di riscrivere programmi C++ in Java, o se non altro di scegliere soluzioni ibride.
Inoltre il nuovo standard JavaBeans, introdotto con il JDK 1.1, introduce un sistema univoco per la progettazione di componenti riutilizzabili, che sicuramente saranno messi a disposizione da molti produttori assieme ad interfacce visuali per gestirli intuitivamente. Questo permetterà ad esempio di costruire interfacce complesse "attaccando" e configurando all'applet componenti già fatti, anzichè usare soltanto gli strumenti "di base" dell'AWT. Questa della modularità e del riutilizzo di componenti è, tra le altre cose, la caratteristica di base della programmazione ad oggetti propriamente detta.


Il nuovo JDK 1.1

La prima novità che si nota nel JDK 1.1 è che è raddoppiato il numero di classi disponibili, infatti sono stati inclusi molti package come il JDBC, che si erano resi disponibili separatamente nei mesi precedenti. A livello di linguaggio vero e proprio le differenze più grandi sono nell'AWT, ad esempio nella gestione degli eventi. Ma vediamo le nuove funzionalità, una ad una, nell'ordine in cui sono presentate nella documentazione Sun.

Internazionalizzazione

Il Java supportava già i caratteri Unicode, che non sono bytes ad 8 bit come gli ASCII, bensì uno standard dove ogni carattere occupa 16bit, in modo da coprire qualsiasi tipo di carattere o simbolo. Il supporto però copriva solo il subset Latin-1, mentre ora è supportato tutto l'Unicode 2.0, sfruttato dalle classi java.text, java.util.Locale e dall'aggiunta nel java.io delle classi Reader e Writer, che sono un InputStream e un OutputStream specifici per i flussi di caratteri, utili anche per convertire flussi di byte in flussi di char, e viceversa. Tramite la capacità della classe java.text di adattare testi, numeri e date alle convenzioni dei diversi paesi, è ora possibile scrivere applicazioni indipendenti dalla lingua, per così dire globali, e la localizzazione nelle diverse lingue si semplifica.
Nella classe java.util.Locale ci sono le variabili delle nazioni e delle lingue, ad esempio ITALIAN e ITALY, JAPAN e JAPANESE, con le dovute distinzione, ad esempio tra il francese del Canada e quello della Francia, o tra l'italiano dell'Italia e quello della Svizzera:

Locale italiano1 = new Locale("it", "IT");
Locale italiano2 = new Locale("it", "CH");

Con queste due linee di codice ad esempio creiamo un Locale per l'italiano dell'Italia e uno per l'italiano del cantone Ticino.

Il package java.security

Java si è distinto come il sistema meno adatto alla manipolazione e "infezione" maliziosa del codice; questa caratteristica viene ora potenziata introducento i signed applet, ossia "applet firmati", estendendo il concetto di sicurezza ad un campo che sta diventando sempre più importante: la riservatezza dei dati.
Il livello di sicurezza delle transazioni di denaro e la segretezza di informazioni importanti determineranno la misura in cui Internet prenderà il posto dei mezzi precedenti. Nel JDK 1.1 c'è il supporto degli algoritmi per la firma digitale come il DSA (Digital Signature Algorithm), con la generazione di chiavi pubbliche e private; la criptazione dei messaggi è supportata con algoritmi come MD2, MD5, e SHA, infine la Access Control List (ACL) si occupa di controllare l'accesso alle risorse, seguendo una lista gerarchica.
Per dare un'idea di cosa sia l'ACL, ecco un pezzo di codice che assegna la capacità di lettura all'utente 1 del gruppo 1:

AclEntry utente1 = new AclEntryImpl(gruppo1);
utente1.addPermission(read);


E' presente anche una utility da eseguire nel prompt dello shell, il "javakey", per la gestione delle chiavi e dei certificati: per aggiungere al database una firma con username pippo, si usa lo switch -cs (create signer):

javakey -cs pippo true

In seguito si può creare una coppia di chiavi pubblica/privata con lo switch -gk (generate key), in questo caso usando l'argoritmo DSA ed una lunghezza di 512 bits:

javakey -gk pippo DSA 51

E' possibile anche generare certificati, i quali certificano il legame tra la nostra chiave e altre entità, ad esempio le applet prodotte dalle sole società che autoriziamo e riconosciamo come partner.


Le grosse modifiche all'AWT.

Al momento di provare a compilare i vecchi listati con il JDK 1.1 molti sono rimasti sorpresi del fatto che compaiono degli errori: come annunciato, l'AWT è stato in parte modificato.
Per fortuna le applet compilate con il JDK 1.02 vengono eseguite dal JDK 1.1 in una sorta di "emulazione" del vecchio AWT, ma se si vuole continuare un nostro progetto con la nuova versione occorre modificare il listato, specialmente nella gestione degli eventi. Dato che le applet compilate con JDK 1.1 non sono eseguibili con una JVM 1.02, come quelle presenti in Netscape ed Explorer versioni 3, le applet saranno compilate col vecchio JDK ancora per molti mesi, o saranno rese disponibili entrambe le versioni 1.02 e 1.1.
Abbiamo visto negli articoli precedenti che gli oggetti derivati dalla classe Component avevano i metodi action(), handleEvent(), mouseUp(), mouseDown() e così via, tramite i quali si gestivano in maniera gerarchica, tramite l'ereditarietà, le azioni dell'utente sulla tastiera, il mouse e le interfacce grafiche.
Questo sistema è stato reso più adatto alla modularità espressa dalle specifiche JavaBeans, dove ogni singolo "Bean" (chicco di caffè) deve potersi interfacciare con l'esterno mantentendo una propria autonomia, secondo la metafora della "sorgente" di eventi e degli "ascoltatori" di tali eventi, che possono essere oggetti anche non derivati da Component. La soluzione adottata è quella di fornire dei metodi "ascoltatori" che possano essere implementati da un qualsiasi oggetto, grazie all'interfaccia java.util.EventListener.
Se col vecchio AWT per sapere quando il mouse era premuto occorreva rifarsi al metodo mouseDown(), col nuovo AWT occorre implementare ll'interfaccia java.awt.event.MouseListener, la quale ci mette a disposizione i seguenti metodi:

mousePressed(MouseEvent e);
mouseReleased(MouseEvent e);
mouseEntered(MouseEvent e);
mouseExited(MouseEvent e);
mouseClicked(MouseEvent e);


Questi sono equivalenti, nell'ordine, a mouseDown(), mouseUp(), mouseEnter(), mouseExit(), mentre l'ultimo è nuovo e registra il "click", ossia pressione e rilascio.
Vediamo una classe pippo, che estende la classe Frame e implementa l'interfaccia MouseListener:

class pippo extends Frame implements MouseListener {

public void mousePressed(MouseEvent e) {
// Eseguire qua le operazioni per mouseDown()
}

public void mouseReleased(MouseEvent e) {
// Eseguire qua le operazioni per mouseUp()
}


Con l'interfaccia MouseMotionListener invece vengono resi disponibili i seguenti metodi:

mouseDragged(MouseEvent e)
mouseMoved(MouseEvent e)


Che sostituiscono i vecchi mouseDrag() e mouseMove().
Il metodo action() è stato diviso in parti: per intercettare gli eventi generati da Button, List, MenuItem e TextField si deve implementare l'interfaccia ActionListener, che ci mette a disposizione il metodo actionPerformed(ActionEvent e), mentre per gli eventi generati da Checkbox e Choice l'interfaccia è ItemListener, il cui metodo è itemStateChanged(ItemEvent e).
Per quanto riguarda WINDOW_DESTROY, WINDOW_ICONIFY e gli altri eventi generati da oggetti Dialog e Frame, l'interfaccia è WindowListener e i metodi sono i seguenti:

windowClosing(WindowEvent e)
windowOpened(WindowEvent e)
windowIconified(WindowEvent e)
windowDeiconified(WindowEvent e)
windowClosed(WindowEvent e)


Da notare che windowClosed non ha equivalenti nel vecchio AWT. Sempre riguardo ai Dialog e ai Frame, l'interfaccia ComponentListener mette a disposizione questi metodi:

componentMoved(ComponentEvent e)
componentHidden(ComponentEvent e)
componentResized(ComponentEvent e)
componentShown(ComponentEvent e)


Di cui solo il primo era disponibile nel vecchio AWT, come WINDOW_MOVED.
Per le Scrollbar l'interfaccia è AdjustmentListener, e il metodo fornito è adjustmentValueChanged(AdjustmentEvent e).
Per la gestione della tastiera l'interfaccia è KeyListener, che ci da in dotazione questi metodi:

keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
keyTyped(KeyEvent)


Da notare che non esiste un equivalente a keyTyped() nel vecchio AWT.
Questo è il nuovo modo di piazzare gli "ascoltatori" (listeners) per intercettare gli eventi, ma dobbiamo informare anche la sorgente della presenza di tali ascoltatori, dichiarandoli in questo modo:

addMouseListener(MouseListener);
addMouseMotionListener(MouseMotionListener);
addItemListener(ItemListener);
addActionListener(ActionListener);


Gli altri li potete intuire. Vediamone l'uso:

Button bottone = new Button("Premi qua");
bottone.addActionListener(this);


Naturalmente la classe deve implementare ActionListener. Alla classe pippo vista precedentemente quindi dobbiamo aggiungere questo costruttore:

public pippo() { // Costruttore
super();
super.addMouseListener(this);
}


Altrimenti gli eventi non saranno "ascoltati" dai metodi listener della classe.
E' possibile anche togliere gli ascoltatori dalla lista di quelli "informati" dalla sorgente:

removeFocusListener(FocusListener);
removeMouseListener(MouseListener);
... eccetera


E' possibile rendere la nostra classe una sorgente di eventi all'ascolto dei quali si possono registrare altre classi: per fare questo si usano i metodi enableEvents() e processEvent().
Spero che questo sia sufficente a rendere l'idea di come fare per aggiornare alla versione 1.1 i vecchi listati.
Altre novità AWT sono la gestione della Clipboard, per l'implementazione delle operazioni taglia e incolla tramite le Java Data Transfer API. Questa capacità non è stata implementata completamente per motivi di tempo nella 1.1, in ogni caso un oggeto, per essere "trasferibile", deve implementare l'interfaccia:

java.awt.datatransfer.Transferable

Mentre per poter ricevere dati col drag and drop deve implementare java.awt.dnd.DropTarget, per esserne sorgente invece deve implementare java.awt.dnd.DragSource.
Sono stati aggiunti anche i menù pop-up (java.awt.PopupMenu), ossia menù in grado di comparire in qualsiasi posizione, a differenza di quelli classici che stanno nella barra menù.
A grande richiesta è stato implementato il supporto per la stampa, tramite java.awt.PrintJob; ecco un esempio di stampa di un componente:

PrintJob pjob = getToolkit().getPrintJob( frame,
"Prova di stampa", (Properties)null );

Graphics pg = pjob.getGraphics();

printAll(pg); // Stampa tutto il componente
pg.dispose(); // Cancella la pagina dalla memoria
pjob.end(); // Fine della stampa


Per evitare che delle applet maliziose facciano partire la stampa di 1000 fogli mentre siamo in navigazione internet, è stato aggiunto un parametro di disabilitazione stampa nelle opzioni della sicurezza.


Il formato di archiviazione JAR.

Il JAR (Java ARchive) è la soluzione ad una mancanza molto evidente del java 1.0, infatti una applet spesso è costituita da molti file .class, i quali non possono essere compressi.
Per questo nel JDK 1.1 è stata inclusa una utility che crea archivi jar, che oltre a fondere tutti i file necessari, li comprime e permette di aggiungere chiavi elettroniche per proteggere l'archivio stesso, con la stessa tecnica che abbiamo visto nel paragrafo sulla sicurezza.


Serializzazione e RMI.

La serializzazione è il processo che si fa quando si deve costruire una struttura dati da salvare, per poi poterla ricaricare in un momento successivo. Con il JDK 1.1 questo compito è stato reso molto più semplice, in quanto anzichè doversi inventare formati e protocolli, perdendo un sacco di tempo e rischiando errori di conversione, basta usare ObjectInputStream e ObjectOutputStream e i rispettivi metodi writeObject() e readObject() per poter salvare e rileggere direttamente strutture di oggetti con relazioni complesse.
Occorre ricordarsi anche di implementare l'interfaccia java.io.Serializable, per rendere gli oggetti serializzabili, ovvero "persistenti". Esiste una apposita utility, il "serialver", che visualizza se una classe è serializzata (e il suo numero identificativo) oppure no.
L'RMI (Remote Method Invocation) è una astrazione del concetto di oggetto remoto e permette una maggiore consistenza del concetto di "applicazioni distribuite", rendendo la comunicazione tra oggetti che si trovano in host diversi un fatto semplice e naturale.


La gestione dei database con JDBC.

La classe java.sql permette di comunicare con un data base remoto che disponga di driver come l'ODBC. Evidentemente questa capacità sarà una delle più richieste per le applicazioni future, assieme a quella della sicurezza di transazioni finanziare in rete.


JavaBeans.

Un Java Bean è un componente "scritto una volta sola e riusabile ovunque", il quale deve poter essere configurato in un ambiente di progettazione visuale di interfacce o tool: questo può comprendere componenti semplici come bottoni o anche cose più complesse come visualizzatori di strutture dati.
Questi componenti devono seguire specifiche ben precise dettate dalla Sun, come la possibilità da parte dei tool di analizzare il funzionamento del Bean (tramite il metodo Introspector.getBeanInfo), il supporto per la persistenza, eccetera. Dato che si tratta di componenti scritti in Java, possono girare su qualsiasi OS, inoltre possono essere usati sia tramite tool wizard, che "a mano", inserendo le necessarie linee di codice nel proprio listato.


I tool di sviluppo

Gli strumenti di sviluppo si stanno portando sempre più verso la programmazione RAD (Rapid Application Development), ossia verso la creazione intuitiva e visuale delle interfacce e della struttura del programma.
Il Java Workshop di Sun ha la caratteristica di essere scritto interamente in Java e in HTML, il che lo rende innovativo e orientato al web, ma anche troppo lento ed avido di memoria per i normali home computer, anche perchè non ha un JIT per velocizzare la JVM.
Il Microsoft Visual J++ e' simile al Visual C++, per cui chi già usa i tool MS si troverà meno spaesato degli altri. La caratteristica più particolare di VJ++ è quella dell'integrazione con la tecnologia proprietaria ActiveX e con Internet Explorer.
Occorre sottolineare che ActiveX funziona solo con Windows e Mac sull'Explorer, quindi si pone in antagonismo con la filosofia multipiattaforma di 100% pure Java e JavaBeans.
Se è vero che ActiveX può rusultare conveniente nelle intranet basate su Windows, lo stesso non si può dire per internet, dove ActiveX viene visto da molti come il solito tentativo di monopolizzazione di Microsoft.
La Symantec è partita per prima con Cafè, e questo vantaggio è mantenuto anche in Visual Cafè, dove la programmazione visuale si spinge un pò più in avanti. Ad esempio l'editing visuale delle interfacce è bidirezionale: se si sposta un gadget nell'applet, cambia automaticamente il codice sorgente, se si cambia il codice sorgente si sposta il gadget.
Il JIT Symantec non è meno veloce di quello in VJ++, ed anche per questo Netscape ha annunciato che lo adotterà nelle prossime versioni di Navigator, al posto di quello usato nella versione 3, che invece è più lento di quello Microsoft.
Altri prodotti in fase di completamento sono: il Borland Latte (Open JBuilder), simile a Delphi e con molte funzionalità per i database, e VisualAge for Java della IBM, che è soprattutto un'ambiente integrato per l'automatizzazione delle reti aziendali.
Infine SuperCede della Asymetrix, ha la caratteristica di poter già creare eseguibili nativi Windows, eventualmente mischiando codice C++ e Java, dato che è compreso anche un compilatore C++. Altra caratteristica è quella di poter modificare i programmi mentre sono in esecuzione.

Fabio Ciucci
fabioc@anfiteatro.it


Torna all' indice degli articoli