LF Java Handbook Rel. 1.0 11.12.2006 Luigi Ferrari Indice 1. GENERALITA'........................................................................................................ 1 1.1. Tipi di programmi in Java.................................................................................................1 1.2. Applicazioni Enterprise.................................................................................................... 1 1.2.1. Servlet....................................................................................................................... 1 1.2.2. JavaBean.................................................................................................................. 1 2. INSTALLAZIONE.................................................................................................... 2 2.1. Windows.......................................................................................................................... 2 2.1.1. Run da DOS.............................................................................................................. 2 2.1.2. Windows 2000 e seguenti......................................................................................... 2 2.2. Linux................................................................................................................................ 2 2.2.1. Configurazione JDK.................................................................................................. 2 2.3. Configurazione server Apache (vedi lfwebserver.txt)...................................................... 3 2.3.1. Accesso al server...................................................................................................... 3 2.4. Organizzazione delle directory.........................................................................................4 2.5. Dove mettere le librerie jar...............................................................................................4 3. USO.........................................................................................................................5 3.1. Operazioni base...............................................................................................................5 3.1.1. Compilazione.............................................................................................................5 3.1.2. Run............................................................................................................................6 3.1.3. Visualizzazione di applet con AppletViewer.............................................................. 6 3.1.4. Visualizzazione di applet da browser........................................................................ 7 3.1.5. Creazione librerie .jar................................................................................................ 7 3.1.6. Creazione librerie .jar eseguibili................................................................................ 7 3.2. JBuilder............................................................................................................................ 7 3.2.1. Costruzione di applicazioni........................................................................................7 3.2.2. Editor......................................................................................................................... 7 3.2.3. Package.................................................................................................................... 8 3.2.4. Uso di librerie............................................................................................................ 8 3.2.5. Inserimento di immagini come sfondo di bottoni o altro............................................ 8 3.3. Bluej................................................................................................................................. 8 3.3.1. Installazione DOS......................................................................................................8 3.3.2. Installazione LINUX...................................................................................................9 3.3.3. Difetti......................................................................................................................... 9 3.3.4. Modo standard di lavorare.........................................................................................9 3.3.5. Uso di librerie (jar)..................................................................................................... 9 3.4. NetBeans......................................................................................................................... 9 3.4.1. Setting dell'editor....................................................................................................... 9 3.5. Eclipse........................................................................................................................... 10 3.6. Progettazione con UML................................................................................................. 10 3.7. Standard SIMS...............................................................................................................10 4. PROGRAMMAZIONE........................................................................................... 11 4.1. Definizioni...................................................................................................................... 11 4.1.1. Classe..................................................................................................................... 11 4.1.2. Attributo................................................................................................................... 11 4.1.3. Metodo.................................................................................................................... 11 4.1.4. Costruttore...............................................................................................................11 4.1.5. Istanza di un oggetto della classe........................................................................... 11 4.1.6. Interfaccia................................................................................................................11 4.2. Regole di scrittura.......................................................................................................... 11 4.2.1. Regole per la scelta dei nomi.................................................................................. 11 4.2.2. Documentazione del codice: utility javadoc.............................................................12 4.3. Tipi di dato..................................................................................................................... 12 4.3.1. Check su variabile booleana restituita come oggetto..............................................12 4.4. Variabili (attributi)........................................................................................................... 12 4.4.1. Modificatori di accesso............................................................................................ 12 4.4.2. Inzializzazione delle variabili................................................................................... 13 4.4.3. Definizione di nuovi tipi di costanti, costanti condivise tra piu' classi...................... 13 4.5. Costruttori...................................................................................................................... 13 4.5.1. Come creare un costruttore che ne richiama un altro............................................. 14 4.5.2. Costruttori private e protected................................................................................. 14 4.6. Metodi............................................................................................................................ 14 4.6.1. Tipi di metodi........................................................................................................... 14 4.6.2. Effetti collaterali....................................................................................................... 14 4.6.3. Modificatori di accesso............................................................................................ 14 4.6.4. Passaggio di parametri............................................................................................15 4.7. Il metodo main............................................................................................................... 15 4.8. this................................................................................................................................. 16 4.9. Stringhe..........................................................................................................................16 4.9.1. Creazione di una stringa......................................................................................... 16 4.9.2. Metodi......................................................................................................................16 4.9.3. Confronto di stringhe............................................................................................... 17 4.9.4. Copia di stringhe..................................................................................................... 17 4.9.5. Buffer per la costruzione di stringhe........................................................................17 4.9.6. Conversione di stringhe da e verso tipi primitivi...................................................... 17 4.9.7. StringTokenizer....................................................................................................... 18 4.10. Array............................................................................................................................ 18 4.10.1. length e arraycopy.................................................................................................18 4.10.2. Array di oggetti...................................................................................................... 19 4.10.3. Passaggio di array ad un metodo..........................................................................19 4.10.4. Array dinamici........................................................................................................19 4.10.5. Oggetti protected...................................................................................................19 4.11. Package....................................................................................................................... 19 5. INTERAZIONE TRA GLI OGGETTI......................................................................20 5.1. Classi interne................................................................................................................. 20 5.2. Ereditarieta'.................................................................................................................... 20 5.2.1. Classi astratte..........................................................................................................20 5.2.2. Oggetti protected.....................................................................................................20 5.2.3. La classe Object......................................................................................................20 5.3. Interfacce....................................................................................................................... 20 5.3.1. Uso delle interfacce: definizione di comportamenti................................................. 20 5.3.2. Uso delle interfacce: definizione di costanti comuni tra le classi.............................21 5.3.3. Esempio d'uso: casello di un ponte......................................................................... 21 5.3.4. Ereditarieta' multipla con Java.................................................................................22 5.4. Composizione................................................................................................................ 23 6. COLLEZIONI DI OGGETTI................................................................................... 24 6.1. Criteri di scelta............................................................................................................... 24 6.2. Iteratori...........................................................................................................................24 6.3. Modalita' di utilizzo......................................................................................................... 24 6.3.1. Uso degli array........................................................................................................ 24 6.3.2. Uso delle ArrayList.................................................................................................. 24 6.3.3. Uso dei Vector.........................................................................................................25 6.3.4. Uso delle mappe..................................................................................................... 26 6.3.5. Uso dei Set (HashSet).............................................................................................26 7. FLUSSI.................................................................................................................. 28 7.1. Scopo.............................................................................................................................28 7.1.1. Flussi di dati, lettori e scrittori.................................................................................. 28 7.2. File di testo: Reader e Writer......................................................................................... 28 7.2.1. Lettura di caratteri da file.........................................................................................28 7.2.2. Schema generale per la lettura............................................................................... 28 7.2.3. Schema generale per la scrittura............................................................................ 29 7.2.4. Metodi di controllo................................................................................................... 29 7.3. File binari: flussi............................................................................................................. 29 7.3.1. Lettura di bytes........................................................................................................29 7.4. Esempio di gestione di flussi di dati: ConsoleReader.................................................... 29 7.4.1. Classe File...............................................................................................................30 7.4.2. Classe FilenameFilter..............................................................................................31 7.4.3. Come creare una directory......................................................................................31 7.5. Flussi di oggetti - serializzazione................................................................................... 31 7.5.1. Serializzazione di oggetti che non implementano Serializable................................32 7.5.2. Serializzazione di oggetti tramite JavaBean............................................................32 7.6. Accesso casuale............................................................................................................ 32 7.6.1. Classe RandomAccessFile..................................................................................... 32 7.7. Flussi su rete di telecomunicazioni................................................................................ 32 7.7.1. Esecuzione di script su server con passaggio di un solo parametro.......................32 7.7.2. Esecuzione di script su server con passaggio di parametri: uncgi..........................33 8. APPLET................................................................................................................ 35 8.1. Caratteristiche................................................................................................................35 8.2. Protezione......................................................................................................................35 8.3. Struttura del file HTML per la chiamata di applet...........................................................35 8.4. Scrittura del codice........................................................................................................ 36 8.5. Passaggio di parametri ad una applet........................................................................... 36 8.6. Classe che fa da applet e da applicazione grafica.........................................................36 8.7. Tips sulle applet............................................................................................................. 37 8.7.1. Memorizzazione di dati su stream (condivisione di dati tra applet)......................... 37 8.7.2. Installazione di applet su Web Server (TO DO)...................................................... 37 8.7.3. Installazione su login diversa da quella del Web Server (TO DO).......................... 37 8.7.4. Come visualizzare un file sul server (TO DO)......................................................... 37 8.7.5. Come lanciare comandi sul server (TO DO)........................................................... 37 8.7.6. Visualizzazione del nome dell'host..........................................................................37 8.7.7. Come aprire una nuova finestra.............................................................................. 37 8.7.8. Come ridisegnare una nuova finestra pop-up su se stessa (TO DO)..................... 38 8.7.9. Come esportare dati da una applet (TO DO).......................................................... 38 8.7.10. Debug e Log di una applet.................................................................................... 38 8.7.11. Messaggi sulla barra di stato.................................................................................38 9. GRAFICA.............................................................................................................. 39 9.1. Gestione degli eventi..................................................................................................... 39 9.1.1. Esempio completo...................................................................................................40 9.2. Classi interne................................................................................................................. 41 9.3. Come combattere lo sfarfallio delle animazioni............................................................. 41 10. SWING................................................................................................................ 42 10.1. Classi........................................................................................................................... 42 10.1.1. JOptionPane..........................................................................................................42 10.1.2. JFrame.................................................................................................................. 42 10.1.3. Menu': JMenuBar, JMenu, JMenuItem, JPopupMenu...........................................43 10.1.4. JButton.................................................................................................................. 43 10.1.5. JFileChooser......................................................................................................... 45 10.1.6. JTable....................................................................................................................45 10.1.7. Layout....................................................................................................................45 10.1.8. JList....................................................................................................................... 45 11. THREAD..............................................................................................................46 11.1. Eventi di un thread....................................................................................................... 46 11.2. Definizione del metodo run()........................................................................................46 11.2.1. Estensione della classe Thread............................................................................ 46 11.2.2. Implementazione dell'interfaccia Runnable........................................................... 47 12. GESTIONE DEGLI ERRORI (EXCEPTION)....................................................... 49 12.1. Eccezioni controllate.................................................................................................... 49 12.2. Eccezioni non controllate............................................................................................. 49 12.3. Gestione delle eccezioni.............................................................................................. 49 12.3.1. Sollevare una eccezione in caso di malfunzionamento.........................................49 12.3.2. Intercettazione delle eccezioni.............................................................................. 50 12.3.3. Creazione di un nuovo tipo di eccezione...............................................................51 12.3.4. Esempi di uso delle eccezioni: FifoQueue............................................................ 51 13. DESIGN PATTERNS.......................................................................................... 54 13.1. Singleton...................................................................................................................... 54 13.1.1. Esempio di implementazione (versione mia, non e' quello classico).....................54 13.2. SenderArgument..........................................................................................................56 13.3. Iteratore........................................................................................................................56 13.4. Observer...................................................................................................................... 57 13.4.1. Realizzazione tramite Observer-Observable.........................................................57 13.4.2. Realizzazione tramite JavaBean........................................................................... 57 13.4.3. Applicazione di Observer: pattern MVC (Model View Controller)..........................58 13.4.4. Java Message Service (JMS)................................................................................59 13.4.5. Problemi del pattern Observer.............................................................................. 59 13.5. Command.................................................................................................................... 59 13.5.1. Insieme di comandi che producono output diversi (es. gitelf)............................... 59 13.5.2. Comando che deve essere lanciato da piu' fonti: Action.......................................60 13.6. Proxy............................................................................................................................62 13.7. Facade......................................................................................................................... 62 14. Esempi di Object Oriented Design...................................................................63 14.1. Forza 4.........................................................................................................................63 15. APPLICAZIONI ENTERPRISE........................................................................... 64 15.1. Servlet..........................................................................................................................64 15.1.1. Esempio di servlet................................................................................................. 64 15.2. JavaBean..................................................................................................................... 64 15.2.1. Creazione di un file jar con il javabean..................................................................64 15.2.2. Loading di un javabean in un IDE......................................................................... 64 16. JDBC - JAVA E I DATABASE............................................................................65 16.1. Connessione e disconnesione dal database............................................................... 65 16.2. Select........................................................................................................................... 65 16.3. Chiamata di stored procedure......................................................................................66 16.4. Insert e delete.............................................................................................................. 66 16.5. Istruzioni DDL.............................................................................................................. 66 17. DATABASE SERVER HSQLDB.........................................................................67 17.1. Installazione................................................................................................................. 67 17.2. Utility............................................................................................................................ 67 17.2.1. DatabaseManager.................................................................................................67 17.2.2. ScriptTool.............................................................................................................. 67 17.3. Versione server............................................................................................................67 17.4. Organizzazione delle dir.............................................................................................. 67 17.4.1. Esempio di script per la creazione di un database................................................68 17.4.2. Esempio di avvio del server.................................................................................. 68 17.4.3. Esempio di avvio del manager del database in versione standalone e server......68 17.4.4. Esempio per vedere il contenuto del database..................................................... 69 18. TIPS: Soluzione di problemi............................................................................. 70 18.1. Standard main - DA RISOLVERE................................................................................70 18.2. log - DA FARE............................................................................................................. 70 18.3. Out Of Memory............................................................................................................ 70 18.4. Attributi che devono contenere valuta..........................................................................70 18.5. Variabili che cambiano valore tra una chiamata e l'altra..............................................70 18.6. Check su variabile booleana restituita come oggetto.................................................. 70 18.7. NullPointerException....................................................................................................70 18.8. Stampa con Java - DA RISOLVERE........................................................................... 70 18.9. Pulizia della memoria (garbace collection forzata)...................................................... 71 18.10. Calcolo del tempo di elaborazione.............................................................................71 18.11. Controllo delle versione della JRE in esecuzione...................................................... 71 18.12. Appleviewer non visualizza applet per problemi con X..............................................71 18.13. Netscape su Linux: visualizzazione di applet.............................................................71 18.14. Errori di arrotondamento............................................................................................ 71 18.15. Conversione decimale-binario................................................................................... 71 18.16. Permissions sulle applet............................................................................................ 72 18.17. Random - Generazione di comportamenti casuali.....................................................72 18.18. Date and Time - Visualizzazione data corrente......................................................... 72 18.19. Date and Time - Classi standard............................................................................... 72 18.20. Problemi con piu' finestre...........................................................................................73 18.21. Configurazione di una applicazione........................................................................... 73 18.22. Associazione di un programma java al tipo di un file sotto Windows.........................73 18.23. Creazione di un link per un programma java............................................................. 74 18.24. Organizzazione di una applicazione in librerie...........................................................74 19. ALGORITMI........................................................................................................ 75 19.1. Strutture dati astratte................................................................................................... 75 19.2. Algoritmi matematici.....................................................................................................77 19.2.1. Potenza n-esima di numero reale (metodo degli invarianti di ciclo)...................... 77 19.2.2. Calcolo della radice quadrata................................................................................77 19.2.3. Calcolo di pi greco con l'ago di Buffon.................................................................. 77 20. ARGOMENTI AVANZATI DI JAVA.................................................................... 79 20.1. Riflessione................................................................................................................... 79 20.2. Riflessione e classi Proxy............................................................................................ 79 20.2.1. Uso di classi proxy per il trace...............................................................................79 21. FONDAMENTI DELLA PROGRAMMAZIONE AD OGGETTI............................ 80 21.1. Oggetti e classi............................................................................................................ 80 21.1.1. Argomenti.............................................................................................................. 80 21.2. Approfondimenti sulla definizione di classi.................................................................. 80 21.3. Interazione tra oggetti.................................................................................................. 80 21.4. Raggruppamenti (collezioni) di oggetti.........................................................................80 21.5. Librerie e documentazione...........................................................................................81 21.6. Test e debug................................................................................................................ 81 21.7. Disegno di classi.......................................................................................................... 81 21.8. Ereditarieta' e polimorfismo..........................................................................................81 21.9. Tecniche avanzate di astrazione: interfacce e classi astratte......................................81 21.10. Gestione degli errori...................................................................................................81 21.11. Disegno di applicazioni.............................................................................................. 81 21.12. Esercizi sui cicli..........................................................................................................81 22. DOCUMENTAZIONE.......................................................................................... 83 22.1. Cay Horstmann, Big java............................................................................................. 83 22.2. Cay Horstmann, Concetti di informatica e fondamenti di java 2.................................. 83 23. API LF................................................................................................................. 84 23.1. lfapi package................................................................................................................84 23.1.1. ConfigFile.............................................................................................................. 84 23.1.2. ConnectionManager.............................................................................................. 84 23.1.3. cpfile...................................................................................................................... 84 23.1.4. EnvironmentMap................................................................................................... 84 23.1.5. FileInputHashMap................................................................................................. 84 23.1.6. FileUtility................................................................................................................84 23.1.7. Log........................................................................................................................ 84 23.1.8. StringUtility............................................................................................................ 84 23.1.9. ThumbnailBuilder.................................................................................................. 85 23.1.10. ThumbnailSetBuilder........................................................................................... 85 23.1.11. txtfile.................................................................................................................... 85 23.1.12. URLReader......................................................................................................... 85 23.2. lfapi.GUI package........................................................................................................ 85 23.2.1. ErrorWindow..........................................................................................................85 23.2.2. GenericTablePanel................................................................................................85 23.2.3. FormLayout........................................................................................................... 85 23.2.4. StatusBar...............................................................................................................85 24. ESEMPI DI CODICE........................................................................................... 86 24.1. JTable con diverse funzionalita'................................................................................... 86 24.2. Form layout.................................................................................................................. 98 LF Java Handbook LF Java Handbook 1. GENERALITA' 1.1. Tipi di programmi in Java Esistono tre tipi di programmi java • applicazioni da console: • applicazioni grafiche: programmi con interfaccia utente gestibile non solo da tastiera, ma anche con il mouse e tramite pulsanti, menu' a discesa, campi per l'inserimento testo, finestre... che forniscono l'intefaccia utente; es: Word, Excel, Bluej.. • applet: che programmi integrati in pagine web e inviate insieme ad esse per aumentare le capacita' dell'HTML (animazioni, interfacce grafiche...). Non possono modificare in alcun modo il contenuto del computer su cui sono eseguite per motivi di sicurezza. 1.2. Applicazioni Enterprise Sono sviluppate per girare su server: sono le servlet. 1.2.1. Servlet Sono eseguite sul server remoto. In pratica una servlet e' una API utilizzata dal Web Server per fornire nuovi servizi. Di solito non hanno alcuna interfaccia grafica. Vengono attivate una volta solo alla attivazione del Server, possono ricordare lo stato. Inoltre possono comunicare tra loro anche attraverso pipeline. 1.2.2. JavaBean work in progress.. -1Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 2. INSTALLAZIONE 2.1. Windows www.javasoft.com -> jdk. Mettere in autoexec.bat il path aggiornato con la c:\programmi\jdk1.2.2\bin) e dichiarare la variabile di ambiente directory bin del jdk (i.e. CLASSPATH con Set: Set CLASSPATH=. Old: Set CLASSPATH=c:\Programmi\jdk1.2.2\lib\classes.zip WINDOWS 1.2.2 da CDROM dev 71 "100% PROGRAMMAZIONE" si installa versione 1.2.2 directory: c:\programmi\jdk122 (era proposto \jdk1.2.2) poi edit \autoexec.bat per aggiungere al PATH c:\programmi\jdk122\bin 1.4.0_01 (su Dell Windows Xp) Directory c:\programmi\java\j2sdk1.4.0_01 Modificata a mano la variabile di ambiente PATH Start/pannello di controllo/prestazioni e manutenzione/Sistema/avanzate/ variabili d'ambiente/path Aggiunto: c:\programmi\java\j2sdk1.4.0_01\bin 2.1.1. Run da DOS Per il run direttamente da DOS nel caso dica che la classe e' NotFound occorre settare classpath in modo da comprendere la directory che contiene il .class. Se non fosse gia' settata puo' bastare set classpath=. 2.1.2. Windows 2000 e seguenti Modifica delle variabili di ambiente con RisorseComputertastodx/Proprieta'/avanzate/Variabili d'ambiente e si modifica la singola variabile. E' necessario essere amministratori. 2.2. Linux 2.2.1. Configurazione JDK User root Si prende J2SDK1.4.0i...BIN (CD Java) e lo si mette sotoo /lftmp poi chmod a+x e lo si esegue. Scompatta nella directory corrente sotto j2sdk1.4.0_01. mkdir /usr/java cp -r j2sdk1.4.0_01 /usr/java login sapilf vi .bash_profile: aggiunto # # Java SDK 1.4.0 (LF 12.3.2003) # JAVA_HOME=/usr/java/j2sdk1.4.0_01 rm -fr $HOME/.netscape/java rm -fr $HOME/.netscape/plugins/javaplugin.so -2Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook export NPX_PLUGIN_PATH=$JAVA_HOME/jre/plugin/i386 cd ~/java mkdir lib login root (copia del driver jdbc di oracle) cd /p3/oracle/817/jdbc/lib cp classes111.zip /home/sapilf/java/lib login sapilf cd java/sapicommon bld -c Compilazione delle api sapi: tutto bene a parte deprecated in SapiExceptionDialog.java. login sapibin mkdir mkdir mkdir mkdir mkdir mkdir Per SIMS il server e' sotto $SAPIBIN_HOME/httpd/html in questa dir ci vanno a finire i .jar (i.e. $SAPIBIN_HOME/httpd/html/login/sapicommon.jar) httpd httpd/html (httpd ci arriva con link da /home/httpd) httpd/cgi-bin httpd/html/dataviewer httpd/html/login httpd/html/cashbook login sapilf cd java/dataviewer bld -c Compilazione e copia librerie... login root (Abilitazione Java Console) vi .bash_profile: aggiunto # # Java SDK 1.4.0 (LF 12.3.2003) # JAVA_HOME=/usr/java/j2sdk1.4.0_01 rm -fr $HOME/.netscape/java rm -fr $HOME/.netscape/plugins/javaplugin.so export NPX_PLUGIN_PATH=$JAVA_HOME/jre/plugin/i386 e settata /bin/bash come shell di default in /etc/passwd Avvio di Netscape e apertura dell'URL file:/usr/java/j2sdk1.4.0_01/jre/ControlPanel.html dove e' possibile settare i parametri della Console Java. Base: - abilita Java plug-in - Mostra console - Mostra finestra di dialogo Eccezioni Avanzate (lasciate le standard) Altre.. lasciate cosi'. 2.3. Configurazione server Apache (vedi lfwebserver.txt) Directory dove mettere i file accessibili del server: /home/httpd/cgi-bin /home/httpd/html In realta', per le esigenze di SAPI html e' un link simbolico a $SAPIBIN_HOME: cd /home/httpd ln -s /vol03/sapibin/httpd/html html 2.3.1. Accesso al server -3Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Linux: utilizzare Netscape. Windows: utilizzare IExplorer. Esempi di URL: http://L3/ /home/httpd/html/index.htm http://L3/oracle.htm http://L3/testapplet/poligono.html http://L3/cgi-bin/test.sh visualizza (se esiste) 2.4. Organizzazione delle directory c:\java (o altro equivalente) bin -> javac, java, appletviewer... lib -> classes.zip 2.5. Dove mettere le librerie jar Ci sono almento tre possibilita': • nella dir lib/ext della jre • nella stessa dir dell'applicazione • in una qualunque dir settando opportunamente CLASSPATH Avevo trovato da qualche parte una bella spiegazione (Guida alla programmazione JSP ?). -4Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 3. USO 3.1. Operazioni base 3.1.1. Compilazione javac [-cp classdir_or_jar] [-d outdir] file1.java [filen.java...] Opzioni: • -cp (classpath) specifica da dove prendere le classi definite negli import. E' possibile dichiarare una directory o un file .jar Se sono piu' di una e' possibile separare dir e file jar con ";". • -d (i.e. ../classes) dice dove creare i .class. ATTENZIONE: sembra che almeno sotto Linux non basti indicare i .jar delle classi nel $CLASSPATH ma sia necessario indicarlo nella linea di comando. i.e.: non trova package netscape.javascript.* dopo lunghe ricerche ho scoperto che e' nella /usr/lib/netscape/java/classes/java40.jar ma occorre compilare con javac -d ../classes -classpath /usr/lib/netscape/java/classes/java40.jar Idem per i driver Oracle messi in $HOME/java/lib/classes111.zip WINDOWS: Sotto windows andare in una shell MS-DOS e spostarsi nella directory dove si vuole mettere il file .java (sorgente). Con edit lo si scrive. Conviene inoltre avere una finestra aperta su edit e una su javac e java. NOTA: sotto DOS non sono ammessi i nomi lunghi per i file (max 8.3). Dir fa vedere file del tipo nomefi~1.jav, ma a destra mostra il nome completo. Per compilare e' necessario dare i comandi con i nomi veri dei file e l'estensione "java". LINUX: Esempio di script sotto Linux per la compilazione automatica #! /bin/sh PACKAGE=shipgate set -a OUTPUT_JAR=$SAPIBIN_HOME/httpd/html/$PACKAGE/$PACKAGE.jar CLASSPATH=$CLASSPATH:\ $JAVA_HOME/jre/lib/javaplugin.jar:\ $HOME/java/lib/sapicommon.jar:$HOME/java/lib/classes111.zip:\ $HOME/java/lib/dx.jar:$HOME/java/lib/dbswing.jar cp $HOME/java/lib/sapicommon.jar $SAPIBIN_HOME/httpd/html/$PACKAGE cp $HOME/java/lib/classes111.zip $SAPIBIN_HOME/httpd/html/$PACKAGE OPTION="none" if [ $# -eq 1 ] then OPTION=$1 fi Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] -5- LF Java Handbook if [ $OPTION = "-c" ] then rm -f classes/$PACKAGE/*.class # compliamo tutti i java inseme poiche' sono correlati javas= for name in src/$PACKAGE/*.java do javas=`echo " ${javas} ${name} "` done name=$javas echo compiling $name ... javac -d classes/$PACKAGE $name REPLY=$? if [ $REPLY != 0 ]; then exit 1 fi echo "all compiled... please wait..." sleep 10 fi cd classes/$PACKAGE echo $OUTPUT_JAR jar cvf $OUTPUT_JAR ./*.class img/* exit 0 3.1.2. Run Attenzione a maiuscole/minuscole java [-cp directory_or_jar] NomeClasse (.class) Se il file (.class) e' in un .jar si deve mettere nell'opzione -cp java -cp NomeFile.jar NomeClasse Se ci fossero piu' dipendenze si devono separare nel cp con ;. Per il run da DOS si deve settare il classpath in modo da comprendere la dir dove e' presente il file .class: set classpath=. in molti casi e' sufficiente. 3.1.3. Visualizzazione di applet con AppletViewer appletviewer URL Attenzione che richiede il .html e non il .class Per lanciare una applet contenuta in un file.jar occorre mettere ARCHIVE= nel tab che invoca la classe. LINUX: Se Appletviewer fallisce dicendo impossibile al server invalid DISPLAY Errore: non puo' trovare server per localhost:0:0 si deve dare da root xhost + che abilita l'accesso al server da qualunque client. DOS Ricordarsi che deve essere stata installata ls JVM (cioe' il JRE) -6Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 3.1.4. Visualizzazione di applet da browser Si ottiene aprendo il file .html. Per visualizzare le applet e' necessario avere installato i plug-in (in pratica la JRE). L'unico libro che ne parla e' Horstmann-Cornell Java2, pag.524 che dice che occorre installare il plug-in... LINUX: Netscape 4.72 non riesce a caricare gli applet: dice che e' un problema di major number. ATTENZIONE: verificare sempre i parametri di lancio delle applet (i.e. ORACLE_SID) 3.1.5. Creazione librerie .jar DOS: bldjar.bat del progetto Gitelf echo off echo echo - Building lfgite.jar ... echo rem copy ..\..\lfcommon\lib\lfapi.jar . cd .. @jar cvf bin\lfgite.jar *.class LogoLF100x100.jpg beansgite\*.class dbgite\*.class rem del lfapi.jar cd bin echo echo - lfgite.jar builded. echo REM @jar cvf dati.jar config data bin txt2xml*.txt @jar cvf dati.jar config echo echo - dati.jar builded. echo if ERRORLEVEL goto err 0 goto ok :err echo "bldjar: ...errore durante l'esecuzione" goto done :ok echo "bldjar successfully executed." :done pause LINUX: vedi prima. 3.1.6. Creazione librerie .jar eseguibili Todo.. 3.2. JBuilder 3.2.1. Costruzione di applicazioni - new Application 3.2.2. Editor • tab stop: e' definito a livello di Project properties, esiste la possibilita' di definire quelli di default. • CTL-SHIFT-<spazio> visualizza i parametri di un metodo -7Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 3.2.3. Package <nomeprogetto>/classes contiene le classi del package Lancio di applicazioni in package javaw Eurino/EurinoApp 3.2.4. Uso di librerie Durante le fasi di sviluppo e' possibile definire delle librerie nelle properties del project (path/Required library). ATTENZIONE: l'ordine e' importante (e difatti e' possibile cambiarlo) JBCL dbSwing oracle2 (classes111.zip) Per utilizzarle durante la fase di running invece non ho ancora trovato come fare direttamente dalla configurazione di run. Conviene invece creare un file html di lancio (che JBuilder lancia con AppletViewer) contenente le direttive ARCHIVE="li1, lib2..". ATTENZIONE: e' necessario far ripartire JBuilder affinche' veda le librerie modificate. 3.2.5. Inserimento di immagini come sfondo di bottoni o altro Non e' possibile direttamente (c'e' la drop list vuota). Occorre prima definire la nuova immagine con ImageIcon nome = new ImageIcon("nomefile.gif"); il file deve essere nella dir dove sta la classe. Attivando designer c'e' in basso a sx il nuovo oggetto <nome> negli Other. FORSE INUTILE: Click sopra, nella finestra a destra si sceglie ImageObserver e li' si indica il bottone o altro che la potra' utilizzare. Andando poi con il designer sul bottone e nella proprieta' Icon dovrebbe essere possibile selezionare l'immagine. 3.3. Bluej E' un ambiente spartano ma molto orientato alla programmazione ad oggetti, scritto in java, per Windows e Linux, free. E' vantaggioso rispetto alla linea di comando da DOS ed ha vantaggi nell'approccio anche rispetto a JBuilder. 3.3.1. Installazione DOS dir di installazione/lib/bluej.defs consente di personalizzare parzialmente l'ambiente: bluej.userHome=E\:\\DellUser\\Luigi\\Java bluej.editor.tabsize=3 #LF bluej.compiler.type=internal bluej.compiler.type=javac bluej.compiler.executable=javac Attenzione: per settare l'apertura della doc delle api di java non serve cambiare il valore in bluej.defs ma e' necessario andare nelle opzioni di bluej: dalla form del programma scegliere Strumenti / Preferenze / Varie e mettere la directory corretta (i.e. -8Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook D:\DocJava\docs\api\index.html). 3.3.2. Installazione LINUX 1. scaricato Bluej-135.jar da www.bluej.org 2. da root mkdir /usr/share/bluej chmod 777 /usr/share/bluej cp xxx/bluej-135.jar /usr/share/bluej xhost + per abilitare l'uso del server da parte di chiunque 3. da sapilf: cd /usr/share/bluej java -cp bluej-135.jar Installer Directory: lasciare /usr/share/bluej Trova da solo la JVM. Crea un eseguibile Bluej vi .bash_profile: aggiunto PATH=$PATH:/usr/share/bluej 3.3.3. Difetti • crea i .class nella stessa dir dei .java (provato modificando bluej.defs mettendo blue.compiler.executable javac -d ../classes (con e senza doppi apici) ma non funziona). • new project: richiede che i file non esistano gia' oppure siano in una dir diversa da quella che si intende creare (e si puo' utilizzare add source from file..). • fino a che e' in esecuzione lock sui file che ha utilizzato, anche su progetti chiusi. • oltre che i .class crea anche del .ctxt nella directory corrente • non ha molte delle facilitazioni dei moderni ambienti di sviluppo: completamento automatico, elenco degli argoemnti dei metodi, collegamento con la documentazione... 3.3.4. Modo standard di lavorare Scelgo dir padre di tutti i progetti (i.e. Luigi/Java/src) New Project-> nome del progetto grosso (i.e. luigi; crea una dir con il nome scelto e ci mette un bluej.pkg) New Package crea sottodir con il suo bluej.pkg Add source from file oppure import da altra dir (copia tutto, comodo) Per prendere dei progetti gia' fatti utilizzare import. 3.3.5. Uso di librerie (jar) Vanno incluse da menu' e occorre ripartire per ricaricarle. Attenzione che, se si modificano, i test non funzionano perche'l'ambiente continua ad utilizzare quelle caricate all'avvio. Per lo sviluppo mettere in ambiente separato e una volta definitive creare .jar, poi far ripartire bluej. 3.4. NetBeans working in progress.. Sembra molto promettente, e' facilmente espandibile, free.. 3.4.1. Setting dell'editor L'editor di default ha dei caratteri molto piccoli. Usare Tools/Options/Editor Settings e poi Java Editor per mettere almeno 16 come dimensione dei caratteri; poi tab size 3. Per la stampa e' necessario scurire i commenti altrimenti nella stampa con laser b/n non si vede nulla. Nella stessa sezione Java Editor scegliere "Font and colors" e mettere 0, 51, 51 per -9Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook i block comments e single line comments. 3.5. Eclipse E' una alternativa a NetBeans, free.. 3.6. Progettazione con UML E' possibile utilizzare Violet (realizzato da Cay Horstmann, free), molto semplice. Alcuni disegni di questo manuale sono realizzati con quello. Una alternativa e' ArgoUML. 3.7. Standard SIMS Si lavora sotto Windows, JBuilder 6 Professional; il collegamento con Oracle c'e' comunque attraverso la rete. Attenzione: jdk deve essere 1.4.0. Per configurare Jbuilder6 con jdk 1.4 occorre mettere il jdk nella directory della versione 1.3. Si copia poi tutto sotto Sun e si ricompila. - 10 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 4. PROGRAMMAZIONE 4.1. Definizioni 4.1.1. Classe Definisce lo stato ed i comportamenti di un insieme di oggetti omogenei. Il suo stato e' definito dagli attributi, il suo comportamento dai metodi. Puo' ereditare stato e comportamenti da un'altra classe (ereditarieta' singola). Puo' implementare nessuna, uno o piu' interfacce (cioe' comportamenti richiesti per poter definire la sua appartenenza ad una categoria, come quella degli oggetti salvabili in un file). Puo' essere necessario anche definire un costruttore. 4.1.2. Attributo Definisce una parte dello stato di un oggetto. Ne esistono di sue tipi. • Variabili di istanza: cambiano fra le istanze • Variabili di classe: uguali per tutti gli oggetti della stessa classe 4.1.3. Metodo Definisce il comportamento della classe. Puo' avere al massimo un valore di ritorno. 4.1.4. Costruttore Serve per costruire un oggetto. Di solito contiene l'inizializzazione dello stato. Il nome del costruttore coincide con quello della classe. Possono essere definiti piu' costruttori, ognuno con parametri diversi in numero e/o tipo. 4.1.5. Istanza di un oggetto della classe Consiste nella creazione di un oggetto della classe. La parola chiave e' "new". 4.1.6. Interfaccia Definisce, senza implementarli, una serie di comportamenti che una classe deve realizzare per poter entrare a far parte di una categoria di classi (ad esempio quelle salvabili su file con una sola istruzione). Possono essere utilizzate anche per definire delle costanti comuni tra piu' classi. 4.2. Regole di scrittura • di ogni classe definire prima di tutto la struttura dati, mettendola in testa e commentandola adeguatamente. • dividere chiaramente le funzioni interne (private) da quelle pubbliche (public) • indicare chiaramente i costruttori 4.2.1. Regole per la scelta dei nomi classi: iniziale maiuscola. attributi e metodi: iniziale minuscola. costanti: tutto maiuscolo. package: tutto minuscolo, se possibile di una sola parola, al singolare. - 11 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 4.2.2. Documentazione del codice: utility javadoc @author @todo 4.3. Tipi di dato int -2e-9 - 2e9 (Integer.MIN_VALUE - Integer.MAX_VALUE) long -9e-18 - 9e18 double 10e300 short 16 bit byte 8 bit, -127 - +128 float 23 cifre binarie, 7 decimali boolean possibili solo i valori true e false. char 2 byte in codifica Unicode BigInteger, BigDecimal: precisione qualunque, sono memorizzati come stringhe BigInteger a = new BigInteger("12345678901234567890123456789012"); ATTENZIONE: i dati primitivi (ad es. i numeri) in Java non sono oggetti, quindi non e' possibile chiamare dei metodi su di loro. NOTA Per le valute usare int, long o BigInteger con unita' di misura il piu' piccolo decimale. Non usare double!! Esistono poi dei tipi di dato che sono Oggetti che rappresentano numeri e altri dati primitivi possono essere utilizzati ovunque sono utilzzati questi, in maniera ovviamente meno efficiente: Integer Integer Float Double Boolean i = new Integer(4); i1 = new Integer("43"); f = new Float(4.0); d = new Double(4.50); b = new Boolean("true"); Conversione: int i2 = i.intValue(); boolean b1 = b.booleanValue(); Conversione da stringa: int i3 = Integer.parseInt("34"); boolean b2 = Boolean.parseBoolean("false"); // metodo statico // metodo statico Da JDK 5.0 la conversione e' invece automatica. 4.3.1. Check su variabile booleana restituita come oggetto if (((Boolean)config.get("DEBUG")).booleanValue()) 4.4. Variabili (attributi) Ci sono variabili della classe, variabili di istanza e variabili locali: • variabili di classe: si dichiarano con static e assumono lo stesso valore in tutte le istanze della classe; se cambio il loro valore in una istanza lo cambio in tutte le altre; • variabili di istanza: sono dichiarate all'interno della classe e sono diverse in ogni istanza • variabili locali: sono dichiarate all'interno dei metodi e sono conosciute solo da loro. Nota: non mettere variabili locali con lo stesso nome dei campi della classe! 4.4.1. Modificatori di accesso • public: chiunque puo' modificare i dati. Da non usare se non in caso di effettiva necessita'. • protected: sono visibili solo nel package (valore di default). • private: si puo' accedere ai campi private solo con i metodi della classe - 12 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook • static: definisce variabili di classe: ce ne e' una per tutte le istanze. Il valore iniziale deve essere assegnato nella dichiarazione (all'atto del caricamento della classe) e non nel costruttore (verrebbe altrimenti cambiata ad ogni nuova istanza della classe) • final: definisce le costanti. Di solito si usa assieme a static per averne una in tutta la classe. Difficilmente si dichiarano costanti non static (sarebbero costanti per il singolo oggetto e non per l'intera classe). Uso: NomeClasse.COSTANTE Esempio: (classe Math): Classe Math: Classe Math: Classe Console: Math.PI (3.1415...) Math.E (2.7178...) System.out 4.4.2. Inzializzazione delle variabili • valore predefinito: al caricamento della classe; • nel costruttore: alla creazione di un nuovo oggetto; • lazy initialization, inizializzazione pigra: solo la prima volta che la variabile viene utilizzata. Si usa un metodo con lo stesso nome (v. Metzker, Design pattern in Java). Esempio di inizializzazione pigra int attributo; public int attributo(int x){ if (attributo == null) attributo = x; return attributo; } 4.4.3. Definizione di nuovi tipi di costanti, costanti condivise tra piu' classi Per fare un controllo sui tipi conviene utilizzare una classe ed una interfaccia (Vedi Metzker Design Patterns - cap.2). Chi le usa deve implementare l'interfaccia (la classe non ha metodi ma solo un costruttore protected vuoto). Definizione: public class Classificazione { protected Classificazione() {} } public interface CostantiClassificazione { static final Classificazione COSTANTE1 = new Classificazione(); static final Classificazione COSTANTE2 = new Classificazione(); } Uso: public class Esempio implements CostantiClassificazione { Classificazione codice; ... if (this.codice == COSTANTE1) ... ... Con l'uso delle interfacce (che sono implementate dalla classe) e' possibile omettere il nome della classe davanti alle costanti utilizzate. 4.5. Costruttori - 13 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 4.5.1. Come creare un costruttore che ne richiama un altro public class NomeClasse { protected int i1; protected NomeClasse next; // e' una lista // prima si mette quello piu' generale public NomeClasse(int el, NomeClasse n) { i1 = el ; next = n ; } public NomeClasse(int el) { this(el, null); } public NomeClasse() { next = null; } ... } 4.5.2. Costruttori private e protected • private: utilizzati quando si usa ad esempio il pattern Singleton (con cui si instanzia sempre un solo oggetto di una classe) • protected: sempre nel Singleton, una mia soluzione permette solo al gestore del pool di risorse di istanziarne di nuove: per far cio' la risorsa e il gestore sono in un package apposito e il costruttore della risorsa e' protected. 4.6. Metodi 4.6.1. Tipi di metodi • Metodi accessori: non modificano lo stato attuale (i.e getSaldo()) Inoltre non modificano il valore dei parametri passati • Metodi modificatori: sono quelli che modificano l'oggetto cui si riferiscono Come regola dovrebbero restituire void. • Metodi statici: non hanno parametri impliciti (cioe' l'oggetto su cui sono chiamati), ma solo espliciti: i.e. Math.sqrt(x) Esistono classi (classi immodificabili) che hanno solo metodi accessori e nessun metodo modificatore: ad esempio la classe String, che non modifica mai il valore dell'oggetto creato: anche il metodo substring restituisce una copia della parte di stringa che si vuole. 4.6.2. Effetti collaterali Si hanno quando i metodi accessori provocano cambiamenti sullo stato o sull'uscita: vedi getSaldo. Graduatoria di comportamento dei metodi: • ottimo: metodi accessori che non producono cambiamenti su eventuali i parametri espliciti. Nessun effetto collaterale (i.e getSaldo) • buono: metodi modificatori che non producono cambiamenti su eventuali parametri espliciti. Nessun effetto collaterale (i.e. prelievo) • sufficiente: metodi che cambiano un parametro esplicito (i.e. trasferisciSu) • insufficiente: metodi che cambiano una variabile statica (cioe' di i classe: se lo chiamo due volte da' risultati diversi) o che stampano messaggi su output (i.e. System.out) 4.6.3. Modificatori di accesso • public: qualunque metodo di qualunque classe che abbia accesso ad una istanza della - 14 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook classe lo puo' chiamare • private: possono essere chiamati solo in metodi della stessa classe; da usare per metodi che non interessano a chi usa la classe e per i metodi che non possono essere facilmente modificati se cambia l'implementazione della classe. • static: agiscono su una classe e non su una istanza per cui possono essere usati senza creare prima l'istanza della classe. Non hanno bisogno di un parametro implicito. Esempio: Math.sqrt(x): il metodo sqrt della classe Math (non di un oggetto Math). Ogni applicazione, ad eccezione delle applet, ha il metodo statico main: infatti all'inzio della esecuzione di un programma non esiste ancora alcun oggetto per cui main DEVE essere statico. Si usano quando si vogliono incapsulare operazioni di tipi esclusivamente numerico (i numeri NON sono oggetti). Di solito conviene metterli in classi separate, simile alla classe Math standard. NOTA: possono accedere solo a campi statici della classe. Esempio: i metodi delle classi Console e Math: double x = Math.pow(3,0,1); Math.round(3.14); ATTENZIONE: non e' possibile utilizzarli applicati ad un numero: errato: corretto: int dolllars = (int)price.round(); int dolllars = (int)Math.round(price); /* ERR */ /* OK */ ESEMPIO: /** * Aggiunge gli interessi ad un conto. * Esempio di metodo statico (o di classe) * La prima versione, commentata, non funziona perche' tenta di modificare * un parametro esplicito NUMERICO */ // public static void aggiornaSaldo(double saldo, double tassoInteresse) // { // double interessi= saldo * tassoInteresse/100; // saldo = saldo + interessi; // } public static void aggiornaSaldo(Conto conto, double tassoInteresse) { double interessi= conto.getSaldo() * tassoInteresse/100; conto.deposito(interessi); } 4.6.4. Passaggio di parametri Avviene per valore per i tipi di dato semplici, per riferimento per gli oggetti. Non e' possibile quindi passare una variabile double e modificarla in un metodo. Non e' possibile cambiare il riferimento ad un oggetto sostituendolo con un altro. 4.7. Il metodo main public static void main (String args[]) throws IOException { for (int i+0; i<args.length; i++) System.out.println("Argomento "+i+" vale "+args[i]); } Note: - 15 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook • arg[0] e' il primo argomento passato (non il nome del programma) • non sono riuscito a trovare l'equivalente di return del C per uscire in caso di errore. • e' definito static perche' deve essere lanciato prima che sia creato un oggetto della classe (anzi, potrebbe non essere mai creato). • il main puo' chiamare solo metodi statici. • la lista di argomenti puo' essere ottenuto come ArrayList. TIP: e' possibile convertire args in una lista anziche' usare l'array di Stringhe (da v. 1.4): public static void main(String args[]) { List argsList = Arrays.asList(args); Iterator it = argsList.iterator(); while (it.hasNext()) { System.out.println("Arg: "+it.next()); } ... } 4.8. this Consente di fare riferimento all'oggetto e non all'istanza particolare: e' da usare ad esempio se si vuole lo stato corrente di un qualsiasi oggetto (parametro implicito del metodo) all'interno di un metodo: Esempio: se per l'oggetto a si chiama il metodo leggi con a.leggi(...) e nel metodo c'e' l'istruzione System.out.println(this) si stampa lo stato corrente dell'oggetto a (infatti System.out.println chiama il metodo toString della classe di a). 4.9. Stringhe Le stringhe sono oggetti "immutabili" per cui non e' possibile, ad esempio, farne direttamente una copia. La stringa nulla ("") e' diversa da null. Non e' possibile derivare delle classi da String (e' final (?)). 4.9.1. Creazione di una stringa String s1 = String s2 = char dati[] String s3 = "abc"; new String("abc"); = {'a', 'b', 'c'}; new String(dati); 4.9.2. Metodi Attenzione: quelli che restiruiscono String non modificano la stringa di partenza, ma restituiscono una nuova stringa. - + concatenazione - String substring(start, primoEscluso) String substring(start) prende fino alla fine Esempio: s = "Hello world"; s.substring(0,4) => "Hell" s.substring(7,12) => "world" - String toLowerCase() - String toUpperCase() - boolean equals(String s) ritorna True se la stringa e' uguale a s passata. - long length() - 16 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook - boolean equalsIgnoreCase(String s) confronto case insensitive String trim() rimuove spazi a inizio e fine stringa. int indexOf(char) -1 se non trovato. char charAt(int i) carattere nella i-esima posizione 4.9.3. Confronto di stringhe String s1 = "Rob", s2 = "Rob", s3, s4 = "Roberto"; String s5 = new String("Rob"); // e' un oggetto sicuramente diverso s3 = s1; Valgono le seguenti regole: - Java ottimizza le stringhe costanti crendo un solo oggetto se sono uguali ("Rob" e "Rob" nell'esempio); - s1 == s2 true (vedi sopra) s1 == s3 true s1.equals(s3) true s1 == "Rob" true (stesso oggetto "Rob") s1 == s4.substring(0,3) false s1.equals(s4.substring(0,3)) true s1 == s5 false 4.9.4. Copia di stringhe Si puo' fare in diversi modi: s2 = s1 + ""; s2 = s1.subString(0); s2 = s1.clone(); 4.9.5. Buffer per la costruzione di stringhe Se si devono costruire delle stringhe a pezzi conviene utilizzare la classe StringBuffer che ottimizza evitando di creare nuovi oggetti per ogni passaggio. L'efficienza aumenta notevolmente. StringBuffer buf = new StringBuffer(); for (int i=0; i < len; i++) { for (int j=0; j< i; j++) buf.append ("*"); buf.append("\n"); } return buf.toString(); 4.9.6. Conversione di stringhe da e verso tipi primitivi Stringa -> tipo primitivo String s1 = new String("320"); String s2 = new String("2.23"); // errato o obsoleto: int i = Integer.ValueOf(s1).intValue(); int i = new Integer(s1).intValue(); meglio ancora: int i = Integer.parseInt(s1); // si usa il metodo statico della classe Integer // errato o obsoleto : double d = Double.valueOf(s2).doubleValue(); double f = new Double(s2).doubleValue(); double d = Double.parseDouble(s2); Tipo primitivo -> stringa int a = 14; int b = 23.33; String s3 = Integer.toString(a); String s4= Double.toString(b); - 17 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Alternative: s3 = String.valueOf(a); s3 = "" + a; // questa e' quella che uso io 4.9.7. StringTokenizer Consente di prendere i token di una stringa. Attenzione che i token vengono eliminati, se servono dovono essere ripristinati. Esempio: StringTokenizer tokenizedLine = new StringTokenizer(line, ","); while (tokenizedLine.hasMoreElements()) { String token =tokenizedLine.nextToken(); // fa qualcosa con token.. } 4.10. Array Dichiarazione di un array private double[] data; // non inizializzato Array inizializzato con tre elementi di tipo string private String[] strarr= { "prima", "seconda", "terza" }; Nel costruttore o altrove si inizializza: data = new double[10]; e si assegnano eventualmente i valori: data[0] data[1] data[2] data[3] data[4] = = = = = 1.0; 1.344; 9.99; 0.998; 1.872; NOTA: gli array sono inizializzati con 0 se sono di int o double con false se sono di boolean, con null se sono array di oggetti 4.10.1. length e arraycopy length, var. istanza, dimensione dell'array, e' final (non modificabile) copia di un array: puo' essere fatta con un ciclo oppure usando il metodo statico arraycopy: System.arraycopy (from, fromStart, to, toStart, count) Esempio: double destinazione[] = new double[sorgente.length]; System.arraycopy(sorgente, 0, destinazione, 0, sorgente.length); - 18 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 4.10.2. Array di oggetti jButton[] bottoni; // dichiarazione bottoni = new jButton[10]; // ora contiene 10 puntatori a null for (int i=0; i<bottoni.length; i++ ) bottoni[i] = new jButton(); // crea oggetto dentro l'array 4.10.3. Passaggio di array ad un metodo public static double media(double[] data) { if (data.length == 0) return 0; double somma = 0; for (int i=0; i< data.length; i++) somma += data[i]; return somma / data.length; } Esempio di chiamata con array creato al volo (anonimo): valMedio = media (new double[] {2.3, 2, 3, 4, 4.09, 8.09, 2.4, 1.55 }); 4.10.4. Array dinamici Gestione di array riempiti solo in parte (array dinamici): • si usa una variabile di appoggio che tiene conto del numero di elementi effettivamente usati (nome: nomearraySize) • ogni volta che si aggiunge un elemento si aggiunge 1 a tale variabile • quando si deve togliere un elemento si compatta l'array • se si raggiunge il massimo si crea un array di dimensioni maggiori (il doppio ad esempio) e si copia il vecchio nel nuovo aggiornando i riferimenti double newData = new double[data.length * 2]; System.arraycopy(data,0, newData, 0, data.length); data = newData; // aggiorna riferimento Una alternativa agli array dinamici e' data dalla classe Vector 4.10.5. Oggetti protected i.e. jPanel nella classe padre La classe figlia puo' aggiungere oggetti all'oggetto protected della classe padre; i pezzi aggiunti sono pero' suoi. 4.11. Package Equivale ad una libreria, contiene piu' classi ed interfacce. La struttura dei file in directory deve rispecchiare la struttura dei package. Per rendere univoco il nome si parte da un URL o da un indirizzo e-mail (i.e. luigife/libero/it/miopackage/miaclasse) package PackageName; public class NuovaClasse { } - 19 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 5. INTERAZIONE TRA GLI OGGETTI 5.1. Classi interne Vedere esempio sotto grafica: Le classi interne. 5.2. Ereditarieta' 5.2.1. Classi astratte Definizione: classe con almeno uno dei metodi definito astratto. Uso: • Classe padre astratta deve poter chiamare i metodi definiti nella classe figlia • Classi che non devono poter essere istanziate (perche' sono prototipi di altre) Regole: Rectangle r; Cuboid c; // Cuboid extends Rectangle. r = c; // sempre ammesso c = r; // vale solo se in realta' r era un Cuboid passato a Rectangle 5.2.2. Oggetti protected i.e. jPanel nella classe padre La classe figlia puo' aggiungere oggetti all'oggetto protected della classe padre; i pezzi aggiunti sono pero' suoi. 5.2.3. La classe Object Metodo equals: si sovrascrive (overriding, non overloading) il metodo equals di Object in modo da poter confrontare oggetti di tipo diverso. Conviene sovrascrivere anche il metodo hashcode() di Object insieme a equals perche questi lo usa: per la classe Object due oggetti sono uguali se hanno lo stesso hashcode. 5.3. Interfacce Il concetto di interfaccia serve per supplire alla mancanza di ereditarieta' multipla in Java. Una classe puo' ereditare da un'altra ed implementare una o piu' interfacce. Una interfaccia definisce i metodi che una classe DEVE definire. 5.3.1. Uso delle interfacce: definizione di comportamenti Quando oggetti di diverse classi devono presentare un comportamento omogeneo riguardo ad una funzione trasversale. Esempio: public interface Comparable { int compareTo(Object o) } NB: tutti i metodi definiti sono public di default e lo devono essere anche nelle classi che la usano. Uso: public class Frazione extends Comparable { - 20 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook ... public int compareTo(Frazione f) { if (this.equals(f)) return 0; if (this.isMinore(f)) return -1; return 1; } public int compareTo(Object o) { if (o istanceof Frazione) { return compareTo((Frazione)o); } } 5.3.2. Uso delle interfacce: definizione di costanti comuni tra le classi Esempio: public interface Mesi { int GENNAIO = 1; int FEBBRAIO = 2; } • Uso 1: senza estendere Mesi: int mese = Mesi.GENNAIO; • Uso 2: con extends Mesi: int mese = GENNAIO; NB non e' necessaria la definizione di static final perche' lo sono di default. Una interfaccia puo' estendere uno o piu' altre interfacce. 5.3.3. Esempio d'uso: casello di un ponte Casello di un ponte: possono passare dei veicoli (ciascuno con la propria tariffa a seconda della tipologia) o delle merci o delle persone. Si crea l'interfaccia "Tariffabile" che prevede il metodo calcolaTariffa(). Nella classe Casello, che contiene una coda FIFO di oggetti di tipo Tariffabile, chiunque sia in coda si chiama su di esso il metodo calcolaTariffa(), senza vedere di quale tipo di tratta. In Veicolo (da cui ereditano Auto, Camion e Moto) il metodo calcolaTariffa e' dichiarato abstract in modo da rendere la classe abstract e obbligare la definizione nelle classi che ereditano. - 21 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 5.3.4. Ereditarieta' multipla con Java Rif: Koffmann, Wolfgang - Objects, astraction, data structures and design using Java version 5.0, Wiley, pag.156 e seguenti. E' possibile con l'uso delle interfacce o con la composizione. Esempio: Classi Studente e Lavoratore, serve la classe StudenteLavoratore. Soluzione con le interfacce: si creano due interfacce StudenteInt e LavoratoreInt, le classi Studente e Lavoratore ne implementano una ciascuna, StudenteLavoratore le implementa entrambe. Problema: non e' possibile definire attributi nelle interfacce. Soluzione con la composizione (o delega): la classe StudenteLavoratore oltre ad implementare le interfacce ingloba due oggetti di tipo Studente e di tipo Lavoratore. Occorre mappare opportunamente i metodi delle interfacce. public class StudenteLavoratore implements StudenteInt, LavoratoreInt { private Studente s; private Lavoratore l; public StudenteLavoratore(String nome, String indirizzo, String scuola, String corso, String ditta, double stipendio) { s = new Studente(nome, indirizzo, scuola, corso); l = new Lavoratore(nome, inidirizzo, ditta, stipendio); } public public public public public public String String String String String double getNome() { return s.getNome();} getIndirizzo() { return s.getIndirizzo();} getScuola() { return s.getScuola();} getCorso() { return s.getCorso();} getDitta() { return l.getDitta();} getStipendio() { return l.getStipendio();} } - 22 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 5.4. Composizione Si riferisce alla proprieta' di passare gli oggetti come parametri ad altri oggetti. - 23 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 6. COLLEZIONI DI OGGETTI Ce ne sono di diversi tipi da utilizzare a seconda dell'uso: Con Java 1.2 (e poi 1.4) e' stata definita un Java Collection Framework che contiene una serie di interfacce nuove per la gestione delle collezioni e che sostituisce le vecchie: • Vecchie:: Vector, HashTable, Enumeration • Nuove:: Set, List, Map, Iterator Conversione dalle vecchie alle nuove: List list = new Vector(); Map map = new HashTable(); 6.1. Criteri di scelta Tipo -------------array ArrayList Vector HashMap TreeMap LinkedHashMap HashSet LinkedHashSet dimensione ---------fissa variabile variabile variabile variabile variabile variabile variabile tipo elementi ------------prim. e ogg. oggetti oggetti key+value key+value key+value oggetti oggetti duplicati ---------si si si non su key non su key non su key no no indice -----si si si no no no no no iteratori --------no si si sincronized? si si ordinata lenta si ordinata si si ordinata 6.2. Iteratori E' un design pattern per esplorare gli oggetti di una collezione che non fa riferimento a metodi specifici del tipo di collezione. import java.util.Iterator Restituisce un Object, utilizzare un cast. NOTA: Si chiede l'elemento successivo all'iteratore, non alla collezione. Esempio: Iterator it = myCollection.iterator(); while (it.hasNext()) { Qualcosa qlc = (Qualcosa)it.next(); } 6.3. Modalita' di utilizzo 6.3.1. Uso degli array Hanno dimensione fissa, funzionano sia con tipi primitivi che con oggetti, usano una sintassi particolare rispetto alle normali classi. Per percorrerlo: for (int i = 0; i < array.length(); i++) {...} 6.3.2. Uso delle ArrayList ArrayList: dimensione variabile, e' una lista di oggetti. Deriva da List. - 24 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook import java.util.ArrayList; Metodi: • add(Object) aggiunge un elemento in coda • Object get(int index) non rimuove l'oggetto dalla collezione • int size() • void remove(int index) ATTENZIONE: la remove provoca la variazione degli indici dell'arrayList. Esempio (con anche uso di iteratori) class ArrayListExample { private ArrayList lista; private int postoLibero; public ArrayListExample(){ lista = new ArrayList(); postoLibero = 1; } public void add(String dsc) { lista.add(new QualcheElemento(postoLibero, dsc)); postoLibero++; } public void percorreListaConCiclo(){ int indice=0; while (indice < lista.size()) { QualcheElemento el = (QualcheElemento)it.get(indice); ... indice++; } public void percorreListaConIteratori(){ iterator it = lista.iterator(); while (it.hasNext()) { QualcheElemento el = (QualcheElemento)it.next(); ... } } public QualcheElemento getElemento(int chiave) { // si spera che non ci siano stati remove, altrimenti non va if (chiave>=1 && chiave < postoLibero) { QualcheElemento el = (QualcheElemento) lista.get(chiave-1); return el; } return null; } } 6.3.3. Uso dei Vector Vector e' praticamente lo stesso che ArrayList. Sono degli array (dinamici, cioe' con contatore degli elementi validi) nascosti nella classe Vector: quando l'array e' pieno se ne crea uno piu' grande e si ricopiano i dati. Se un record di una variabile Vector non mantiene il proprio valore ma lo cambia ad ogni aggiunta di un nuovo record significa che e' stata definita static (cioe' e' una variabile di classe e non di istanza) Metodi: • int capacity() capacita' del vettore (?) • int size() numero di elementi contenuti • Object elementAt(int index) • void setElementAt(Object obj, int index) • void insertElementAt(Object obj, int index) inserisce un elemento nella posizione index, spostando i successivi in avanti di uno - 25 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook • void addElement(Object obj) aggiunge in fondo al vettore • void removeElementAt(int index) rimuove l'elemento; sposta indietro gli elementi successivi • boolean removeElement(Object obj) rimuove l'elemento passato se presente restituendo true, oppure restituisce false • int indexOf(Object el) restituisce la prima posizione dell'oggetto el del vettore, -1 se non trovato 6.3.4. Uso delle mappe Una mappa e' una collezione di oggetti chiave/valore, in numero variabile. Ciascun elemento e' una COPPIA di oggetti, cui si accede indicando la chiave e non l'indice come invece accade negli ArrayList. Sono usate se si conosce la chiave e si vuole conoscere il valore (sono "a senso unico"). Esempio di mappa: agenda (chiave nome, valore = stringa dei numeri di telefono) Sottoclasse: HashMap Metodi: • void(?) put (key, value) • Object get (key) Sottoclasse: TreeMap. Si tratta di una mappa ordinata. Esempio preso da CalEve - Gestione eventi del Calvino TreeMap listaEventi; Nel costruttore: listaEventi = new TreeMap(); Inserimento di un elemento: listaEventi.put(evento.getKey(), evento); Ricerca di un intervallo di elementi e iterazione su di essi: ATTENZIONE che se si specifica lo stesso valore di chiave per from e to si ottiene l'insieme vuoto. public String[] getEventi(int gg,int mm,int aaaa) { String fromKey, toKey; fromKey=""+(aaaa*10000+mm*100+gg); if (gg==0) { toKey=""+(aaaa*10000+mm*100+50); }else{ toKey=""+(aaaa*10000+mm*100+gg+1); } SortedMap subList=listaEventi.subMap(fromKey, toKey); sm=subList; Iterator it = subList.entrySet().iterator(); int num = subList.entrySet().size(); // numero di elementi trovati String[] eventi= new String[num]; int count=0; Evento e = null; while(it.hasNext()) { String key =(String)((Map.Entry)it.next()).getKey(); //System.out.println("key = "+key+"."); e=(Evento)listaEventi.get(key); eventi[count]=e.getDay()+" / "+mm+" / "+aaaa+" : "+e.getDescr(); count++; } return eventi; } 6.3.5. Uso dei Set (HashSet) Sono insiemi di oggetti, esiste un unico item per ogni oggetto distinto (non ci sono duplicati). Non e' garantito alcun ordine nell'esplorazione. E' possibile utilizzare comunque Iterator. - 26 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook - 27 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 7. FLUSSI 7.1. Scopo Consentire la gestione di informazioni provenienti da fonti eterogenee, fra cui i supporti di dati non volatili (e si parla di persistenza). 7.1.1. Flussi di dati, lettori e scrittori Per la memorizzazione di dati si possono utilizzare: • il formato testo (sequenza di caratteri: come codifica Java utilizza i codici Unicode a 32 bit, il numero 12345 viene memorizzato in cinque caratteri '1' '2' '3' '4' '5' utilizzando in totale 10 byte). In questo caso si parla di lettori (reader) e scrittori (writer). • il formato binario (sequenza di byte: 12345 viene memorizzato in 4 byte contenenti 0 0 48 57) che e' piu' compatto ed efficiente ma non e' direttamente interpretabile con un editor di testo. Per i file binari si parla di flussi. Tutte queste classi sono definite nel pacchetto java.io. 7.2. File di testo: Reader e Writer Se si utilizza il formato testo si devono utilizzare le classi Writer e Reader (e le loro sottoclassi): per leggere da disco si usa un oggetto FileReader, per scrivere FileWriter: FileReader reader = new FileReader("input.txt"); Metodi: read , write: questi sono gli unici metodi forniti per queste classi: il loro compito e' solo quelle di leggere o scrivere singoli dati, non di analizzarli. Se si vogliono fare operazioni piu' complesse e' possibile combinare queste classi con altre. Quando si e' finito di utilizzare un file e' necessario chiudere il lettore o lo scrittore r.close(). 7.2.1. Lettura di caratteri da file La classe Reader ha il metodo read che legge un carattere alla volta (FileReader usa il metodo sovrascritto per estrarre i caratteri da un file su disco): tuttavia il metodo read di fatto restituisce un int in modo da poter segnalare sia che e' stato letto un carattere sia che e' stata raggiunta la fine dell'input (attraverso il valore -1). Si usa un cast per ottenere il carattere: Reader r = ... int next = r.read(); char c; if (next != -1) c = (char)next; 7.2.2. Schema generale per la lettura E' piu' conveniente leggere linee piuttosto che caratteri singoli. Essendo pero' la lunghezza di una linea indefinita si usa una classe che si occupa di restituire stringhe di caratteri a partire da un Reader: si usa cioe' un BufferedReader: try{ BufferedReader reader = new BufferedReader(new FileReader("filename")); String line = reader.readLine(); while(line!=null) { - 28 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook //fa qualcosa con line line= reader.readline(); } reader.close(); } catch (FileNotFoundException e) { // file non trovato } catch (IOException e) { // problemi durante la lettura o la chiusura } 7.2.3. Schema generale per la scrittura try{ FileWriter writer = new FileWriter("filename"); while( /* c'e qualcosa da scrivere */) { ... writer.write(/* testo da scrivere */); } writer.close(); } catch (IOException e) { // problemi durante le operaizoni sul file } 7.2.4. Metodi di controllo La classe File possiede dei motodi che possono essere utilizzati prima di aprire il file per evitare di tentare con sicuro fallimento: • exists() • canRead() Vanno utilizzati soprattutto con la lettura di file binari, con la scrittura di solito non e' necessario che il file esista. 7.3. File binari: flussi Se si utilizza il formato binario si parla di flussi e si utilizzano le classi OutputStream e InputStream (e sottoclassi): per leggere da disco si usa la sottoclasse FileInputStream, per scrivere FileOutputStream: FileInputStream input = new FileInputStream("input.dat"); 7.3.1. Lettura di bytes Il metodo read legge int (16 bit), a noi servono byte (8 bit). Si usa un cast per ottenere il carattere: InputStream in = ... int next = in.read(); byte b; if (next != -1) b = (byte)next; Utilizzare le eccezioni per gestire i molti casi di eventi inattesi (fine file, nome file errato, impossibile creare file in scrittura..). 7.4. Esempio di gestione di flussi di dati: ConsoleReader Utile per l'input da tastiera senza utilizzare l'alternativa delle finestre di dialogo (di Cay Horstmann). Scopo: leggere caratteri, numeri, linee da console. 1. L'oggetto System.in di tipo InputStream ha un solo metodo (read) per la lettura di byte. Ogni carattere e' codificato in Java con due byte (Unicode). - 29 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Terminologia: • Flussi di input: (binari): leggono byte • Lettori: (Reader) (testo): leggono caratteri Convertiamo il flusso di input System.in in un oggetto reader: InputStreamReader reader = new InputStreamReader(System.in); 2. I lettori leggono singoli caratteri: bufferizziamo in modo da leggere piu' caratteri e restituirli a blocchi: BufferedReader console = new BufferedReader(reader); 3. BufferedReader ha un metodo readLine String input = console.readLine(); ATTENZIONE: occorre gestire in questo caso le eccezioni, usare un blocco try { ...} catch.. 4. conversione in numero: int numero = Integer.parseInt(input); Esempio di lettore da tastiera public class ConsoleReader { private BufferedReader reader; public ConsoleReader (InputStream inStream) { reader = new BufferedReader(new InputStreamReader(inStream)); } public int readInt(){ String s = readLine(); return Integer.parseInt(s); } public double readDouble() { String s = readLine(); return Double.parseDouble(s); } public String readLine() { String inputLine = ""; try { inputLine = reader.readLine(); } catch(IOException e) { System.out.println(e); System.exit(1); } return inputLine; } } 7.4.1. Classe File import.java.io.*; Note: dato che possono generare eccezioni e' necessario specificare "throws IOException" dopo main. Dichiarazione: File file=new File(nomefile); Metodi: public boolean canRead() public boolean canWrite() public boolean exists() public String getCanonicalPath() public String getName() public boolean isDirectory() - 30 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook public long length() public String[] list() vale solo per le directory public String[] list(FilenameFileter f) restituisce la lista dei file della directory che rispondono al criterio specificato nel filtro passato (v. Dev n.58) 7.4.2. Classe FilenameFilter import.java.io.*; Note: (v. Dev 58) serve per filtrare i nomi dei file del metodo list della classe File. 7.4.3. Come creare una directory Versione che funziona anche se mancano le directory padre: in pratica si fa la ricorsione utilizzando StringTokenizer sul percorso da creare. Il tentativo di metterlo in una classe e' mio. src/mkdir.java static class FileUtility { /** Crea una directory creando pero' anche eventuali genitori se non esistono */ static void mkdir(String percorsoCompleto) { StringTokenizer tokenDirectory = new StringTokenizer(percorsoCompleto, "\\"); StringBuffer stringaSottoDirectory = new StringBuffer(""); while (tokenDirectory.hasMoreElements()) { stringaSottoDirectory.append(tokenDirectory.nextToken()).append("\\"); File sottoDirectory = new File(stringaSottoDirectory.toString()); if (!sottoDirectory.exists()) { sottoDirectory.mkdir(); } } } } 7.5. Flussi di oggetti - serializzazione E' sufficiente aggiungere implements serializable all'interfaccia della classe. C.Horstmann, Concetti di informatica e fondamenti di Java 2, p.583 (p.514 su Java 5). Per essere serializzabile un oggetto deve contenere sottoclassi TUTTE serializzabili. Ad esempio nel caso di un cliente che contiene un indirizzo Vedi class Cliente implements Serializable { private String nome; private Indirizzo ind; } la classe Indirizzo deve essere anch'essa serializzabile (se non lo fosse vedi capitolo successivo). Uso public class Test { public static void main(String[] args){ Cliente c; File f = new File ("Clienti.dat"); if (f.exists()) { ObjectInputStream in = new ObjectInputStream( new FileInputStream(f)); c = (Cliente)in.readObject(); } else { c = new Cliente(...); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 31 - LF Java Handbook } c.add(...); ObjectOutputStream out = new ObjectOutputStream ( new FileOutputStream(f)); out.writeObject(c); out.close(); } } 7.5.1. Serializzazione di oggetti che non implementano Serializable Il problema si pone qunado un oggetto che si intende serializzare contiene delle variabili istanza di classi non serializzabili. E' il caso, ad esempio, di alcuni oggetti geometrici che non sono serializzabili a causa della dimenticanza dei progettisti. La soluzione e' di prevedere dei metodi che salvano le singole istanze degli oggetti utilizzando esplicitamente la parola chiave transient. Vedi C.Horstmann, Concetti di informatica e fondamenti di Java 2, p.586 (p.516 su Java 5). Attenzione: si devono dichiarare due metodi PRIVATI appositi che salvino i dati delle variabili non serializzabili e li ripristinino alla fine. 7.5.2. Serializzazione di oggetti tramite JavaBean A partire da Java 1.4 e' statp introdotto un nuovo metodo per la persistenza di oggetti, che produce dei file XML e che per questo viene chiamata "long term bean persistence". Vedere doc di Java, classe java.Beans.XMLEncoder. E' utilizzata ad esempiodal programma Violet di K. Horstmann. 7.6. Accesso casuale Vedi C.Horstmann, Concetti di informatica e fondamenti di Java 2, p.587 (p.505 in Java 5) 7.6.1. Classe RandomAccessFile import.java.io.*; Dichiarazione: RandomAccessFile file=new RandomAccessFile(nomefile,"rw"); Metodi: public void close() public long getFilePointer() restituisce la posizione corrente all'interno del file public long length() dimensione del file public final byte readByte() public final String readLine() public void seek(long n) posiziona il puntatore alla byte n del file con n che vale RAfile.lenght si va a finefile public final void writeBytes(String s) scrive sul file s a partire dalla posizione corrente. Sovrascrive se non siamo a fine file. 7.7. Flussi su rete di telecomunicazioni 7.7.1. Esecuzione di script su server con passaggio di un solo parametro Non sono necessarie particolari attenzioni: e' sufficiente passare il valore del parametro di seguito all'URL preceduto da un ?. Frammento di codice; per URL reader vedi paragrafo subito dopo void buildPanel(String cgi, String par) { - 32 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook String url=cgi+"?"+par; JTextArea text = new JTextArea(); try { URLReader ur= new URLReader(url); String line; while ((line=ur.readLine())!=null) { System.out.println(line); text.append(line+"\n"); } System.out.println("End."); } catch (Exception e) { text.append("Exception on: " + cgi +" parameter "+par+ ".\n"); text.append("Exception " + e + ".\n"); } 7.7.2. Esecuzione di script su server con passaggio di parametri: uncgi Sul server deve essere installato uncgi (io ho versione 1.11). Per Struttura delle dir e per un esempio di uncgi script vedi manuale WebServer. Si deve aprire un URL come connessione e inviare i parametri con il metodo get. Esempio import java.util.*; import java.io.*; /** * Read from a URL with a uncgi script. * Send parameters on command line (GET method) * * @author L. Ferrari - [email protected] * @version 1.0 21.9.2004 * @history 1.0 Versione originale */ public class ProcessConfigReader { public ProcessConfigReader(){ } public static void main(String arg[]) { String urlString; if (arg.length == 0) { urlString = "http://l3/cgi-bin/uncgi/testlf.cgi"; }else{ urlString=arg[0]; } HashMap par= new HashMap(); par.put("par1","prova1"); par.put("par2","/tmp/esempio.txt"); par.put("par3","34.7890"); try { URLReader ur= new URLReader(urlString,par); String line; while((line=ur.readLine())!=null){ System.out.println("Read: "+line); } System.out.println("End."); } catch (FileNotFoundException e) { System.out.println("File: " + arg[0]+File.separator+arg[1]+ " not found."); } catch (IOException e) { System.out.println("Error on file: " + urlString + ".\n"+e); } catch (Exception e) { System.out.println("URLReader: Exception on: " + urlString +"\n"+e); } System.exit(0); } } ----------------------------------------------------------------------------------------import java.net.*; import java.io.*; import java.util.Iterator; import java.util.Set; import java.util.Map; /** * Generic and specific URL reader.<p/> * Contructors open the URL and send to it parameters if necessary. * - 33 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook * @author L. Ferrari - [email protected] * @version 1.0 7.10.2004 * @history 1.0 Versione originale */ public class URLReader { private BufferedReader in; private URL url; private HttpURLConnection urlConn; /** Open a URL and a buffered reader for it. * @param urlString input URL. */ public URLReader(String urlString) throws Exception { this.url= new URL(urlString); urlConn=(HttpURLConnection)this.url.openConnection(); urlConn.setDoInput(true); urlConn.setUseCaches(false); urlConn.setAllowUserInteraction(true); in = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); } /** Open a URL who is a cgi or uncgi script and put it a list of parameters.<p/> * Parameters will be sended with GET method, into par1=val1&par2=val2&par3=val3... form. * * @param urlString source URL * @param par map of parameters. They will be encoded before send to URL. */ public URLReader(String urlString, Map par) throws Exception { this.url= new URL(urlString); urlConn=(HttpURLConnection)this.url.openConnection(); urlConn.setDoOutput(true); PrintWriter out = new PrintWriter(urlConn.getOutputStream()); Set keyValues = par.entrySet(); Iterator it = keyValues.iterator(); String mapStr="\n"; while(it.hasNext()) { Map.Entry en=(Map.Entry)it.next(); out.print((String)en.getKey()+"="+ java.net.URLEncoder.encode((String)en.getValue(),"ISO-8859-1")); if (it.hasNext()) out.print("&"); mapStr+= " " + en.getKey() + " = "+en.getValue()+ "\n"; } System.out.print("DEBUG: URLReader: properties:"+mapStr); out.close(); in = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); } /** Close the URL */ public void close() throws Exception{ in.close(); } /** Print URL content on standard output */ public void printOut() throws IOException{ String line; while ((line=in.readLine())!=null) System.out.println(line); } /** Read a line from URL * @return a line read from URL or null if no data found. */ public String readLine() throws IOException{ return in.readLine(); } } - 34 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 8. APPLET 8.1. Caratteristiche Le applet sono come dei programmi grafici ma vengono eseguite all'interno di un browser Web. Il codice di una applet e' conservato in un server Web (a livello di bytecode) e viene scaricato nel browser quando si accede alla pagina che contiene l'applet. Vantaggi: • non e' necessario essere sul proprio PC per eseguirla • puo' essere aggiornata senza operazioni presso l'utente: si aggiorna solo il codice sul server (comodo ad esempio nelle Intranet) • e' indipendente dal sistema operativo Svantaggi: • deve essere scaricata dalla rete ogni volta 8.2. Protezione Questo metodo potrebbe prestarsi alla diffusione di virus su tutti i computer che accedono alla pagina contenente la applet. Per evitarlo le applet hanno due meccanismi di protezione: • si possono firmare • si possono eseguire con diversi privilegi di sicurezza Per impostazione predefinita una applet viene eseguita dalla Java Virtual Machine con privilegi molto limitati: • puo' visualizzare informazioni e ricevere input da parte dell'utente • non puo' eseguire programmi sul pc locale • non puo' effettuare operazioni di I/O (lettura/scrittura su file) sul pc locale • non puo' effettuare chiamate verso metodi nativi (cioe' che si interfacciano direttamente con l'hardware del pc) • non puo' stabilire connessioni con altre macchine oltre a quella da cui e' stata scaricata Esempio: non funzionano il taglia/incolla da TextArea della Applet (mentre va se lo stesso programma e' lanciato come Frame). 8.3. Struttura del file HTML per la chiamata di applet <HTML> <HEAD> <TITLE>EsempioApplet Applet</title> </head> <body> <p> ESEMPIO DI APPLET</p> <APPLET CODE="EsempioApplet.class" ARCHIVE="libreria1.jar,libreria2.jar" ORACLE_SID="T" WIDTH=500 HEIGHT=500 > Testo alternativo alla applet se il browser non e' abilitato <PARAM NAME="Squadra" VALUE="Sampdoria"> </APPLET> </body> </html> - 35 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook NOTE: • il testo e' utilizzato solo nel caso che il browser non sia in grado di gestire le applet. • archive: e' necessario che nella parola chiave archive ci siano tutti i file jar da cui occorre prendere le classi, separati da virgole. • archive: non e' possibile usare due tag archive separati. • archive: Bluej versione 1.3.5 ha problemi con la crezione dei .jar se si sono cambiati i nomi delle classi. Fare attenzione che non rimangano le vecchie. Nel dubbio cancellare i .class e ricostruirli prima di metterli nei .jar. 8.4. Scrittura del codice • nella dichiarazione della classe si aggiunge "extends Applet" • non esiste metodo main • sono previsti cinque metodi di gestione, con comportamento predefinito ma che possono essere riscritti. init, eseguito una sola volta all'inizio start, eseguito subito dopo init e dopo ogni sospensione del funzionamento, ad esempio per il passaggio ad un'altra finestra paint, eseguito ogni volta che c'e' necessita' di ridisegnare l'applet (ad es. dopo ridimensionamento finestra) stop, eseguito ogni volta che l'utente esce dalla pagina Web che contiene le applet destroy, richiamato del web browser quando l'applet puo' essere rimossa completamente dall'applicazione 8.5. Passaggio di parametri ad una applet Consentono di cambiare il comportamento della applet senza doverla ricompilare: possono essere specificati nella pagina HTML che contiene la chiamata alla applet: <APPLET CODE="AppletProva" WIDTH=300 HEIGHT=140> <PARAM NAME="Squadra" VALUE="Sampdoria"> <PARAM NAME="Rosso" VALUE="1.0"> </APPLET> e possono essere letti nel codice con getParameter(), ad esempio nel metodo init della applet: String squadra = getParameter("Squadra"); float rosso = Float.parseFloat(getParameter("Rosso")); String parametro = get Parameter("IMAGESOURCE"); imageSource = (parametro == null) ? getDocumentBase() : new URL..; 8.6. Classe che fa da applet e da applicazione grafica In pratica e' sufficiente aggiungere il metodo main. public class AppletEFrame extends Applet { ... public static void main(String args[]){ Frame f = new Frame("Titolo del frame"); AppletEFrame aef = new AppletEFrame(); aef.init(); aef.start(); f.add("Center", aef); f.setSize(800,600); f.setVisible(true); } - 36 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Ci andrebbero aggiunti anche i listener per la chiusura della finestra. E' possibile fare lo stesso con JApplet e JFrame: public class JAppletEJFrame extends JApplet { ... public static void main(String args[]){ JAppletEJFrame a = new JAppletEJFrame(); JFrame f = new JFrame("Titolo del frame"); // "Applet: " +a.getClass().getName(); f.setSize(800,600); f.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { System.exit(0); } }); f.getContentPane().add(a); a.init(); f.setVisible(true); } Vedere anche altri esempi nel Java Tutorial e il libro Java di Camagni-Nikolassay (UD6, p.205). 8.7. Tips sulle applet 8.7.1. Memorizzazione di dati su stream (condivisione di dati tra applet) Dalla versione 1.4 di Java e' possibile memorizzare dati di una applet su degli stream di caratteri, e lo stesso stream puo' essere letto da altre applet SULLA STESSA MACCHINA. Una applet puo' aprire un numero indefinito di stream e ognuno di essi e' accessibile mediante una chiave. Per un esempio vedere Sun: Core Java Technigies Tips del 14 marzo 2006, provato sotto Luigi/Java/Sun (classe StreamsApplet). L'ho provato lanciando due finestre del browser e gli stream creati su una era modificabili sull'altra. Ci possono essere problemi di sincronizzazione. Gli streams sono accessibili fino a che almeno una delle applet rimane viva. 8.7.2. Installazione di applet su Web Server (TO DO) 8.7.3. Installazione su login diversa da quella del Web Server (TO DO) 8.7.4. Come visualizzare un file sul server (TO DO) 8.7.5. Come lanciare comandi sul server (TO DO) 8.7.6. Visualizzazione del nome dell'host Puo' essere inserito come informazione nell'help della applet. import java.net.URL; String host=getCodeBase().getHost(); Attenzione che se si puo' lanciare anche come applicazione non puo' leggere il valore (da' exception). 8.7.7. Come aprire una nuova finestra Esempio (CCSapiControlCenter) JDialog f = new JDialog(); f.setTitle(getSelectedProcess().name+" configuration"); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 37 - LF Java Handbook f.setModal(true); JComponent c = (JComponent) f.getContentPane(); c.add(new ConfigPanel(getSelectedProcess().name, getSelectedProcess().getConfig()), BorderLayout.NORTH); f.pack(); f.setVisible(true); repaint(); 8.7.8. Come ridisegnare una nuova finestra pop-up su se stessa (TO DO) 8.7.9. Come esportare dati da una applet (TO DO) 8.7.10. Debug e Log di una applet Scrivere su System.out non e' una soluzione accettabile, almeno in fase di rilascio del programma. E' possibile condizionarle con una variabile: if (debug) System.out.println(...) Altra soluzione e' utilizzare una classe per il log da attivare a livello di parametro della applet. Altra soluzione e' utilizzare la barra di stato (brutta soluzione perche' non e' garantiro funzioni). 8.7.11. Messaggi sulla barra di stato Si usa il metodo showStatus(String s). Non utilizzarlo per inserire informazioni cruciali, ma solo informative: potrebbero essere sovrascritte dal browser. - 38 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 9. GRAFICA 9.1. Gestione degli eventi NOTA: vedi anche il pattern Observer e il pattern Command. I programmi moderni consentono all'utente di avere il controllo del flusso del programma. Esempi di strumenti di controllo del flusso che possono generare degli eventi: pressione di tasti, clic del mouse, pressione di pulsanti. In Java e' il gestore delle finestre di Java che gni volta che accade un evento significativo invia una comunicazione al programma. Il numero di eventi puo' essere enorme (es. evento "movimento del mouse"). Il programma, per non essere sommerso da segnalazioni di eventi non significativi, indica quali eventi gradisce ricevere grazie all'installazione di oggetti "intercettatori di eventi" (event listener). In piu' esistono "tipi" diversi di eventi (eventi di tastiera, di movimenti e di clic del mouse): per ogni tipo ci sono diverse classi di event listener. Per installare un listener occorre conoscere l"origine" dell'evento: essa e' il componente dell'interfaccia utente che genera un determinato evento. Esempi: un pulsante e' l'origine degli eventi per il clic del mouse, una voce di menu' e' l'origine per un evento di selezione di menu', una barra di scorrimento e' l'origine per un evento di regolazione della barra di scorrimento. Sono coinvolte tre classi: • la classe evento: per il mouse e' MouseEvent, che puo' indicare le coordinate x,y del puntatore del mouse e quale pulsante del mouse e' stato premuto; • la classe dell'intercettatore (listener): per il clic del mouse deve essere una classe che implementa l'interfaccia MouseListener. Questa interfaccia ha molti metodi, che vengono chiamati quando si preme un pulsante del mouse, quando lo si rilascia... Ciascuno di questi metodi ha un parametro MouseEvent. • l'origine dell'evento. E' il componente che genera l'evento del mouse: nel nostro caso e' la applet, nella cui area occupata dello schermo l'utente puo' fare clic con il mouse. Dobbiamo dire alla applet quali listener del mouse bisogna avvertire quando si verifica un evento del mouse. Tutte le classi evento sono sottoclassi di EventObject che ha un metodo getSource che restituisce l'oggetto che ha generato l'evento. Le sottoclassi hanno i loro metodi per descrivere ulteriormente l'evento: ad esempio MouseEvent ha i metodi getX e getY. Diagramma di ereditarieta' EventObject | AWTEvent / \ ActionEvent ComponentEvent / \ InputEvent WindowEvent / \ MouseEvent KeyEvent La parte piu' complessa e' individuare il listener: per esempio il listener del mouse deve implementare l'interfaccia MouseListener e i cinque metodi seguenti: public interface MouseListener { - 39 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook void mouseClicked (mouseEvent e); chiamato quando si e' fatto clic su un componente void mouseEntered (mouseEvent e); chiamato quando il cursore del mouse entra in un componente void mouseExited (mouseEvent e); chiamato quando il cursore del mouse esce da un componente void mousePresseded (mouseEvent e); chiamato quando un pulsante del mouse e' stato premuto void mouseReleased (mouseEvent e); chiamato quando un pulsante del mouse e' stato rilasciato } La nostra classe sposta una ellisse disegnata dalla applet nella posizione dove si fa clic con il mouse. Possiamo mettere la classe che implementa il listener in due punti, pur rimanendo nello stesso file: a. come classe separata dalla classe applet: va bene se non dobbiamo accedere a variabili istanza della applet (ad esempio se volessimo solo spiare e stampare su System.out) class MouseSpy implements MouseListener { void mouseClicked (mouseEvent e) { System.out.println(" Clic: x = " + e.getX() } void mouseEntered (mouseEvent e) { System.out.println("Enter: x = " + e.getX() } void mouseExited (mouseEvent e) { System.out.println(" Exit: x = " + e.getX() } void mousePresseded (mouseEvent e) { System.out.println("Press: x = " + e.getX() } void mouseReleased (mouseEvent e) { System.out.println(" Rel.: x = " + e.getX() } } public class MouseSpyApplet extends Applet { public MouseSpyApplet () { MouseSpy listener = new MouseSpy(); addMouseListener(listener); } } + " y = " + e.getY()); + " y = " + e.getY()); + " y = " + e.getY()); + " y = " + e.getY()); + " y = " + e.getY()); b. come classe "interna" alla classe applet: questa soluzione e' necessaria ogni volta che dobbiamo accedere a delle variabili istanza della classe applet. E' la soluzione usata nell'esempio. Per evitare di dover implementare tutti e cinque i metodi anche se alcuni non ci interessano, conviene utilizzare una classe adapter che semplicemente implementa i 5 metodi come "non fare niente": Definizione della classe MouseAdapter // e' definita nel pacchetto java.awt.event public class MouseAdapter implements MouseListener { void mouseClicked (mouseEvent e) {} void mouseEntered (mouseEvent e) {} void mouseExited (mouseEvent e) {} void mousePresseded (mouseEvent e) {} void mouseReleased (mouseEvent e) {} } 9.1.1. Esempio completo import import import import import java.applet.Applet; java.awt.Graphics; java.awt.Graphics2D; java.awt.geom.Ellipse2D; java.awt.event.*; - 40 - Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook public class GestioneEventi extends Applet { private Ellipse2D.Double puntatore; private static final double DIAMETRO = 15; public GestioneEventi() { puntatore = new Ellipse2D.Double (0,0, DIAMETRO, DIAMETRO); // intercettatore degli event del mouse MouseClickListener l = new MouseClickListener(); addMouseListener(l); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.draw(puntatore); } // definizione dela classe interna per la gestione del mouse private class MouseClickListener extends MouseAdapter { public void mouseClicked (MouseEvent e) { int mouseX = e.getX(); int mouseY = e.getY(); puntatore.setFrame(mouseX - DIAMETRO/2, mouseY - DIAMETRO/2, DIAMETRO, DIAMETRO); repaint(); } } 9.2. Classi interne Si noti che la classe interna accede alla variabile istanza "puntatore" della classe esterna (perche' non ha variabili istanza che si chiamano cosi'). La classe esterna costruisce un oggetto della classe interna e lo aggiunge come intercettore degli eventi di mouse. L'oggetto della classe interna ("l" nel nostro caso) si ricorda dell'oggetto che lo ha costruito: in via eccezionale il metodo della classe interna ha il privilegio di accedere a variabili istanze PRIVATE della classe esterna: sembra pericoloso ma in realta' il pericolo c'e' con le variabili istanza PUBBLICHE, cui tutti possono accedervi, mente qui si tratta sempre della stessa classe. Il metodo setFrame non produce effetti sulla visualizzazione sullo schermo, semplicemente aggiorna l'oggetto Java che contiene la posizione del cerchietto sullo schermo. Dobbiamo ridisegnare: non possiamo utilizzare il metodo paint() perche' ci servirebbe un oggetto Graphics che non abbiamo: potremmo procurarcelo ma non sarebbe comunque una buona soluzione, perche' non si deve chiamare direttamente il metodo paint() per non interferire con il gestore delle finestre. Conviene invece dire alla applet di ridisegnare se' stessa, alla prima occasione possibile: si usa il metodo repaint(), che a sua volta chiama il metodo paint() al momento opportuno e con un oggetto Graphics adatto. La chiamata a repaint() e' fatta nel metodo mouseClicked della classe MouseClickListener: ovviemente tale classe non ha il metodo repaint(), quindi il compilatore lo cerca nella classe esterna, dove lo trova (ereditato dalla superclasse Component), e lo chiama. Su quale oggetto e' stato invocato il metodo? su quello della classe esterna (cioe' l'applet che ha costruito il listener). Le classi interne sono piuttosto particolari, molto utili per intercettare eventi ma difficilmente utilizzate per altri scopi. Conviene utilizzarle utilizzando lo schema generale. 9.3. Come combattere lo sfarfallio delle animazioni Vedere articoli - Ridefinizione del metodo Update - Doppio Buffering - 41 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 10. SWING E' una alternativa a AWT, con diversa filosofia: ridisegna i componenti nello stesso modo sotto tutti gli ambienti, mentre AWT usa le primitive del sistema operativo. Il doppio buffering e' incluso. 10.1. Classi (v. 9.4) 10.1.1. JOptionPane Esempi di uso JOptionPane.showMessageDialog(null,"Messaggio da mostrare", JOptionPane.INFORMATION_MESSAGE); String input = JOptionPane.showInputDialog("Scegli il valore da assegnare alla cella"); if (input== null) return; if (Character.isDigit(input.charAt(0))) { int valore=Character.digit(input.charAt(0),10); target.setValore(valore); }else{ JOptionPane.showMessageDialog(null,"messaggio", "Titolo", JOptionPane.WARNING_MESSAGE); } TIPS: • nel metodo showInputDialog e' necessario gestire la scelta "Annulla" verificando che la stringa non sia nulla (vedi esempio sopra). Esempio di messaggio di warning su una operazione, i.e in una actionPerformed int ret = JOptionPane.showConfirmDialog(null, "Sei sicuro di voler uscire\ndal programma?","Esci",JOptionPane.YES_NO_OPTION,JOptionPane.WARNING_MESSAGE); if (ret == 0) // 0 per si, 1 per no System.exit(0); 10.1.2. JFrame E' la classe principale per la crezione di un aapplicazione grafica. Esempio: come creare un frame che testi un componente grafico. public class JXXX extends JPanel { public JXXX () { setPreferredSize(new java.awt.Dimension(400,400)); setMinimumSize(new java.awt.Dimension(400,400)); ... } ... public static void main(String [] args) { JFrame f = new JFrame(); f.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); // alternativa a implememtare il listener. f.setTitle("Test del componente JXXX"); f.setSize(600,480); f.setForeground(java.awt.Color.blue); // Per specificare il comportamento in chiusura: f.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { System.exit(0); // nel caso di piu' sorgenti per la chiusura // utilizzare la chiamata di un metodo } }); JXXX c = new JXXX(); - 42 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook f.getContentPane().add(c); f.pack(); f.setVisible(true); // adatta alle dimensioni del contenuto } } Note sui metodi: • getContentPane: Serve per aggiungere componenti al frame, che non possono essere aggiunti direttamente con add. • pack: Adatta la finestra ai componenti che ci sono dentro, forse anche se si e' chiamato setSize() (da confermare). • setVisible: Mostra il frame. Precedentemente si utilizzava show, deprecato da java 5. Main che lancia un JFrame Per evitare deadlock con swing e awt non conviene eseguire semplicemente la new ma utilizzare un thread apposito (v. Winder-Roberts Developing Java Software, p.334). public class AJFrame extends JFrame { ... public static void main(String [] args) { SwingUtilities.invokeLater(new Runnable() { public void run() {new AJFrame();} }); } } 10.1.3. Menu': JMenuBar, JMenu, JMenuItem, JPopupMenu Per la costruzione di menu' si utilizzano diverse classi: • JMenuBar: una barra di menu' che puo' essere aggiunta al frame corrente oppure in un qualsiasi contenitore (i.e. JPanel). • JMenu: un menu' con piu' voci ed eventuali sottovoci. Per aggiungere un separatore utilizzare JMenu m ... m.addSeparator(); • JMenuItem: una voce di menu (puo' essere sostituito da una Action). Consente di definire alcune proprieta' dell'item in un colpo solo (ad esempio icona, tasto accelleratore etc.). • JMenuPopup: un menu' che puo' essere aggiunto ad un qualsiasi componente ed essere attivata, ad esempio, con il click dx del mouse. Esempio d'uso in progetto sudoku; doc in Fondumental of swing: Part I, short course (stampato). Tips: Per aggiungere uno spazio tra un menu' a discesa e il successivo utilizzare: JMenuBar menuBar = new JMenuBar(); menuBar.add(createMenu("Menu1")); menuBar.add(Box.createHorizontalGlue()); menuBar.add(createMenu("Help")); // separatore Attenzione: una volta che un menu' e aggiunto ad un JMenuBar non puo' essere utilizzato in altri punti. Per poter fare la stessa azione con piu' tipi di interfaccia (bottoni, menu, ...) si devono utilizzare le action (vedi esempio nella parte di grafica). 10.1.4. JButton - 43 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Vedi esempio Grafica/ButtonDemo.java. ATTENZIONE: per gestire i menu Popup non si puo' utilizzare il metodo JPopupMenu.setInvoker() ma occorre definire una classe interna listener come nel seguente esempio (preso da sudoku). ... private JButton button; private JPopupMenu popupMenu; public AJPanel() { ... button.setHorizontalAlignment(SwingConstants.CENTER); button.setText(""+cella.getValore()); button.setBackground(Color.WHITE); button.setEnabled(false); button.setAction(new CellaAction("CLICK",null, this)); button.setBorder(null); popupMenu = new JPopupMenu(); popupMenu.add(new JMenuItem(new AnAbstractAction("azione1", null, this)); popupMenu.addSeparator(); popupMenu.add(new JMenuItem(new AnAbstractAction("azione2", null, this)); // non va: popupMenu.setInvoker(button); MouseListener popupListener = new PopupListener(popupMenu); button.addMouseListener(popupListener); this.add(button); update(); } ... /** Classe interna presa dal tutorial di Java per gestire il popup su un bottone * che altrimenti non funziona. */ class PopupListener extends MouseAdapter { JPopupMenu popup; PopupListener(JPopupMenu popupMenu) { popup = popupMenu; } public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } /** Classe interna per la gestione delle azioni effettuate sulla cella. */ class AnAbstractAction extends AbstractAction { private AComponent target; public AnAbstractAction(String name, Icon icon, Component comp) { putValue(Action.NAME, name); putValue(Action.SMALL_ICON, icon); target = (AComponent)comp; } public void actionPerformed(ActionEvent evt) { String name=(String)getValue(Action.NAME); System.out.println("AnAbstractAction: Action "+name+" command: "+evt.getActionCommand()); // popupMenu: if (name.equalsIgnoreCase("azione1")) { String input = JOptionPane.showInputDialog("Inserisci un numero intero"); if (input== null) return; if (Character.isDigit(input.charAt(0))) { int valore=Character.digit(input.charAt(0),10); target.setValore(valore); }else{ JOptionPane.showMessageDialog(null,"Valore non ammesso! Riprova!", "Valore errato", - 44 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook JOptionPane.WARNING_MESSAGE); } }else if (name.equalsIgnoreCase("Azione2")) { JOptionPane.showMessageDialog(null,"Ciao!", "Titolo: ciao!", JOptionPane.INFORMATION_MESSAGE); // Click sul bottone }else if (name.equalsIgnoreCase("CLICK")) { System.out.println("CellaAction: Click on "+ target.getId() + " > " +target.getValore()); } target.update(); // aggiorna componente che ha attivato l'action } } 10.1.5. JFileChooser Vedi esempio in GiteLF. 10.1.6. JTable Implementa il pattern MVC. tips: • setPreferredSize(new java.awt.Dimension(400,400)); Vedi esempi. 10.1.7. Layout Si applicano ad esempio a Jpanel. Predefiniti: BorderLayout FlowLayout GridLayout 10.1.8. JList Una JList e' un elenco di voci, selezionabile. JList filtrate Per filtrarle e' possibile utilizzare un filtro come descritto un Sun, Core Java Technologies Tips del 14 Dicembre 2005 (fatto sotto Jdk 1.5, che ho portato sotto JdK 1.4.2 sotto Dell8500/Users/Luigi/Java/Sun, classi FilteringJList e il frame Filters). Con il filtro l'utente digita una stringa e il modello in autometico mantiene solo le voci che contengono la stringa utilizzata come filtro. - 45 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 11. THREAD I thread sono utilizzati in ogni programma Java. Un thread e' un singolo algoritmo sequenziale all'interno di un programma. Esso ha un inizio, una serie di istruzioni eseguite in sequenza e una fine. Un thread non puo' essere eseguito in maniera indipendente, ma solo all'interno di un programma. In un programma che richiede un unico flusso del programma non e' necessario preoccuparsi esplicitamente del thread: esso viene creato e gestito dalla JVM (Java Virtual Machine) in maniera trasparente ed automatica. Uno dei punti di forza del linguaggio Java e' che e' possibile programmare piu' thread all'interno di un unico programma in maniera molto semplice. Esempio: un browser web puo' eseguire il dowload di un file da un sito e contemporaneamente visualizzare un altro sito, senza aspettare che abbia finito il download. La JVM esegue sempre piu' thread simultaneamente, i Deamon threads: ad esempio c'e un thread che gestisce la garbage collection, un altro resta in attesa degli eventi del mouse ed un altro di quelli della tastiera. E' possibile da un programma modificare il compertamento di questi thread. Attenzione con l'uso del pattern Singleton (Metsker, Pattern design, p.83) 11.1. Eventi di un thread Un thread ha un suo ciclo di vita ben definito: • start: inizio • stop: fine del ciclo di vita • pause: puo' stare fermo per un periodo di tempo • wait: attesa di un evento • run: puo' scambiare informazioni con altri thread. 11.2. Definizione del metodo run() Il metodo run() definisce il comportamento di un thread. Per implementarlo ci sono due strade possibili: • 1.: estendere la classe java.lang.thread • 2.: implementare l'interfaccia java.lang.Runnable 11.2.1. Estensione della classe Thread La classe Thread ha un metodo run() che deve essere ridefinito; si crea una nuova istanza della classe con new(); si eseguo una istanza chiamando il metodo start() che a sue volta chiama il metodo run(). Esempio package ProcessiConcorrenti; /** * <p>Title: Corso di Java -</p> * <p>Description: esempio di uso dei thread estendendo la classe thread</p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: </p> * @author Luigi Ferrari * @version 1.0 del 22.3.2003 */ public class Contatore extends Thread { Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 46 - LF Java Handbook private int inizio; private int fine; public Contatore(int da, int a) { this.inizio=da; this.fine=a; } public void run() { System.out.println(this.getName()+ " partito..."); for (int i=inizio; i<= fine; i++) { System.out.println(this.getName() + ": " + i); //attende un tempo casuale inferiore al secondo try { sleep((int) Math.random() * 1000); // max 1 sec } catch(InterruptedException e) {} } System.out.println(this.getName()+ " finito."); } public static void main(String[] args) { Contatore contatore1 = new Contatore(1,10); Contatore contatore2 = new Contatore(20,30); contatore1.start(); contatore2.start(); } } 11.2.2. Implementazione dell'interfaccia Runnable Occorre: • implementare il metodo run() nella classe; • creare una istanza della classe con new(); • creare una nuova istanza della classe Thread con new(), passando come parametro l'istanza della classe creata • invocare il metodo start() dell'oggetto Thread creato, provocando la chiamata di run() Il vantaggio di implementare l'interfaccia Runnable e' che la classe puo' ereditare da qualsiasi altra classe, aumentando la liberta' del programmatore. Esempio package ProcessiConcorrenti; /** * <p>Title: Corso di Java - Processi concorrenti</p> * <p>Description: uso dei thread implementando la interfaccia runnable * </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: </p> * @author Luigi Ferrari * @version 1.0 */ public class ContatoreRunnable implements Runnable { private int inizio; private int fine; public ContatoreRunnable(int da, int a) { this.inizio=da; this.fine=a; } public void run() { System.out.println(Thread.currentThread() + " partito..."); for (int i=inizio; i<= fine; i++) { System.out.println(Thread.currentThread() + ": " + i); //attende un tempo casuale inferiore al secondo try { Thread.currentThread().sleep((int) Math.random() * 1000); // max 1 secondo di attesa } catch(InterruptedException e) {} - 47 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook } System.out.println(Thread.currentThread()+ " finito."); } public static void main(String[] args) { ContatoreRunnable contatore1 = new ContatoreRunnable(1,10); ContatoreRunnable contatore2 = new ContatoreRunnable(20,30); new Thread(contatore1).start(); new Thread(contatore2).start(); } } - 48 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 12. GESTIONE DEGLI ERRORI (EXCEPTION) La soluzione tradizionale al malfunzionamento e' quella che il metodo restituisce un indicatore sia nel caso di successo che in quello di insuccesso (i.e: readLine restituisce o una stringa o null). Questo approccio ha due problemi: • 1: il chiamante potrebbe dimenticare di controllare il valore restituito • 2: il chiamante potrebbe non essere in grado di gestire un insuccesso: se non sa come rimediare potrebbe lasciare al suo chiamante di gestirlo a sua volta: bella seccatura per il programmatore che si trova a dover gestire potenziali mafunzionamenti annidati nei metodi utilizzati. Questa metodologia inoltre tende a far programmare "pensando all'insuccesso" if (!x.faQualcosa()) return false; anziche' pensando al successo: x.faQualcosa(); In piu' il programma diventa di difficile lettura e quindi manutenzione. Il meccanismo di gestione che usa le eccezioni risolve questi problemi: • le eccezioni (almeno quelle controllate) non possono essere ignorate • le eccezioni possono essere gestite da un gestore "competente" e non solo dal chiamante del metodo fallito 12.1. Eccezioni controllate Esempio: tutte quelle che derivano da IOException Sono quelle che dipendono da eventi prevedibili, il cui accadere dipende, ad esempio, dall'uso che l'utente fa del programma (i.e tenta di aprire un file che non esiste, o che non e' del formato corretto) Il compilatore deve sapere cosa fare con queste eccezioni. ATTENZIONE: esistono casi di eccezioni che dovrebbero essere controllate (cioe' dovrebbe essere richiesto sempre un gestore) e che invece non lo sono: ad esempio Integer.parseInt lancia NumberFormatException che e' non controllata. Cio' non vieta di installare un gestore... 12.2. Eccezioni non controllate Esempio: quelle che estendono RuntimeException o Error Sono quelle dovute da un errato uso dell'oggetto da parte del PROGRAMMATORE e quindi non prevedibili (i.e. tentare di leggere da un file che non e' stato possibile neppure aprire: il puntatore e' null) 12.3. Gestione delle eccezioni 12.3.1. Sollevare una eccezione in caso di malfunzionamento E' la parte piu' facile: basta chiamarla. Esempio: si stanno leggendo dei record da file costituiti da tre linee ognuno. Se ad un certo punto dopo la prima riga di un record il file finisce non siamo in una condizione corretta. String in = readLine(); if (in == null) { EOFException exc = new EOFException ("Fine file in lettura"); throw exc; } oppure - 49 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook String in = readLine(); if (in == null) throw new EOFException ("Fine file in lettura"); dopo aver sollevato l'eccezione il metodo finisce immediatamente, come se si fosse eseguito un return 12.3.2. Intercettazione delle eccezioni Se una eccezione non e' intercettata da un qualche gestore il programma si blocca. E' neccessario quindi preparare un gestore per ogni tipo di eccezione che puo' accadere. Un gestore delle eccezioni si installa con un blocco try contenente delle clausole catch. Esempio try { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Quanti anni hai?"); String inLine = in.readLine(); -- puo' sollevare IOException int age = Integer.parseInt(inLine); -- puo' sollevare NumberFormatException age++; System.out.println("L'anno prossimo avrai " + age + " anni."); } catch (IOException e) { System.out.println("Errore input/output"); } catch (NumberFormatException e) { System.out.println("L'input non era un numero."); } finally { -- da eseguire sia in caso di eccezione che normalmente -- solitamente contiene ad esempio la chiamata alla close dei -- file aperti } Esempi di gestione delle eccezioni a) ORRENDO nasconde il problema: catch (myException e) {} b) Stampa dello stack (meglio che niente) catch (myException e) { e.printStackTrace(); } c) messaggio di log catch (myException e) { System.out.println("input errato: " +e); } d) gestione di ritentativi in caso di errore esempio (contalinee) boolean done = false; String filename = JOptionPane.showInputDialog("Nome del file:"); BufferedReader reader; int counter = 0; while (!done) { try { reader = new BufferedReader(new FileReader(filename)); // usa il file... ad esempio contandone le linee while(!done) { String input = reader.readLine(); if (input == null) done = true; // fine del file else counter++; } } catch (IOException e) { System.out.println("Input/output error: "+e); } catch (NumberFormatException e) { e.printStackTrace(); } if (!done) { // concede un'altra possibilita' filename=JOptionPane.showInputDialog("Prova un altro file:"); if (filename==null) // se non inserisce nulla finisce done=true; - 50 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook } } 12.3.3. Creazione di un nuovo tipo di eccezione a) si sceglie da chi estendere a seconda che si richieda sia sempre creato un gestore o no (vedi Gestioni controllate e non) b) si crea una nuova classe contenente solo due costruttori: public class myException extends RuntimeException { public myException() {} public myException(String ragione) { super(ragione); } } la "ragione" e' la stringa che viene mostrata nella JVM quando accade l'eccezione e si stampa lo stack 12.3.4. Esempi di uso delle eccezioni: FifoQueue src/FifoQueue.java /** Gestione di una coda di numeri interi, con gestione delle eccezioni. * @author Luigi Ferrari * @version 1.1 del 31.1.2004 */ /** Eccezioni della coda FIFO */ class CodaVuotaException extends RuntimeException { public CodaVuotaException () {} // Nessuna gestione implicita } class CodaPienaException extends RuntimeException { // posso mettere piu' costruttori, anche con parametri public CodaPienaException (String motivo) { System.out.println("CodaPienaException: motivo: " + motivo); } } class IndiceErratoException extends RuntimeException { public IndiceErratoException (int x) { System.out.println("IndiceErratoException: la posizione " + x + " non esiste"); } } /** Coda FIFO */ public class FifoQueue { private int[] dati; private int puntoInserimento; private int puntoEstrazione; private int datiPresenti; /** Costruttori */ public FifoQueue(int dim) { dati = new int[dim]; puntoInserimento = 0; puntoEstrazione = 0; datiPresenti = 0; } public FifoQueue() this(100); } { /** Inserisce un dato nella coda * @param x dato da inserire * @return none, CodaPiena exception generate if queue is full */ public void insert(int x) throws CodaPienaException { if (datiPresenti == dati.length) throw new CodaPienaException("Inserzione di " + x); dati[puntoInserimento] = x; puntoInserimento++; if (puntoInserimento == dati.length) puntoInserimento = 0; datiPresenti++; } - 51 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook /** Estrae un dato dalla coda * @return dato estratto */ public int get() throws CodaVuotaException { int dato; if (datiPresenti == 0) throw new CodaVuotaException(); dato = dati[puntoEstrazione]; puntoEstrazione++; if (puntoEstrazione == dati.length) puntoEstrazione = 0; datiPresenti--; return dato; } /** Indica se la coda e' vuota. * @return true se la coda e' vuota, false altrimenti */ public boolean isEmpty() { if (datiPresenti == 0) return true; return false; } /** Restituisce un dato della coda. Utile se volio fare una interfaccia grafica * che visualizzi il contenuto della coda * @param pos posizione nell'array (0..(N-1)) * @return il dato nella posizione indicata */ public int getDato(int pos) throws IndiceErratoException { if (pos >= dati.length || pos < 0) throw new IndiceErratoException(pos); return dati[pos]; } /** Debug */ public void show(String s) { System.out.println(s + ": pInserimento " + puntoInserimento + " pEstrazione " + puntoEstrazione + " datiPresenti " + datiPresenti); for (int i=0; i<dati.length; i++) System.out.println("Dati["+i+"]="+dati[i]); } } Classe di test (src/FifoQueueTest.java) /** Test della classe FifoQueue */ public class FifoQueueTest { public static void main(String[] args) { FifoQueue f = new FifoQueue(5); try { for(int i=1; i<5; i++) f.insert(i); System.out.println ("estrae 1: " + f.get()); f.insert(5); f.insert(6); System.out.println ("Fallisce l'inserimento:"); f.insert(7); // commentare se si vuole provare l'altra eccezione } //try catch (CodaVuotaException e) { System.out.println("BLOCCO TRY..CATCH: Impossibile estrarre, coda vuota"); } // catch catch (CodaPienaException e) { System.out.println("BLOCCO TRY..CATCH: Impossibile inserire, coda piena"); } // catch finally { // eventuali istruzioni da eseguire comunque System.out.println("BLOCCO FINALLY"); } try { System.out.print("Contenuto della coda:"); for (int i = 0 ; i<=5; i++) System.out.print(" "+f.getDato(i)); } //try catch (IndiceErratoException e) { System.out.println("BLOCCO TRY..CATCH: Passato indice errato a getDato"); } // catch try { while (!f.isEmpty()) // svuota la coda System.out.println ("estrae: " + f.get()); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 52 - LF Java Handbook System.out.println("Fallisce l'estrazione perche' coda vuota:"); int x=f.get(); // fallisce, coda vuota! System.out.println("Di qui non dovrebbe passare..."); } //try catch (CodaVuotaException e) { System.out.println("BLOCCO TRY..CATCH: Impossibile estrarre, coda vuota"); } // catch finally { // eventuali istruzioni da eseguire comunque System.out.println("BLOCCO FINALLY: FINE DEL PROGRAMMA"); } } } - 53 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 13. DESIGN PATTERNS 13.1. Singleton Riferimenti: • Singleton: : Design Patterns, Mokabyte n.64 Maggio 2002 Giancarlo Crocetti. • Objetc pooling: : Mokabyte n... Giovanni Tommasi. • Metzker, pattern design, p.83: esempio che usa il monitor della classe per evitare problemi con i threads. Si usa per avere una singola istanza di una classe. Caratteristica principale: • un costruttore privato che garantisce la singola istanza • un costruttore pubblico e statico getIstance() Struttura base del Singleton public class Singleton{ private static Singleton instance = null; private Singleton () { ...} public static Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; } //altri metodi } Esempi di uso: • connection pool • generazione di SID globali • DesktopView 13.1.1. Esempio di implementazione (versione mia, non e' quello classico) Note: • per rendere impossibile allocare risorse ad altri che il Gestore che usa il singleton ho incapsulato la risorsa e il suo gestore di pool in un package separato e ho dichiarato il costruttore della risorsa protected. • per liberare una risorsa potrebbe bastare il free del riferimento senza passare per la ricerca nell'array` • nell'esempio il Singleton e' duplicato e i metodi sono tutti statici: <<< e' possibile migiorare separando la richiesta di una istanza del pool dalla concessione dell'istanza della risorsa Risorsa r = Pool.getInstance().getRisorsa(); src/GestoreRisorse/PackageRisorse/GestoreRisorse.java package PackageRisorse; import java.util.ArrayList; import java.util.Iterator; /** Gestisce un pool di risorse. * Usa il pattern Singleton. * Utilizza una classe interna RisorsaIncapsulata che contiene la risorsa * e il suo stato * @author L.Ferrari * @version 1.0 del 31.1.2004 - 54 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook */ public class GestoreRisorse { // instance variables - replace the example below with your own static private GestoreRisorse instance = null; private static ArrayList pool; private static final int NUM = 3; /** Costruttore */ private GestoreRisorse() { pool = new ArrayList(); for (int i=0; i< NUM; i++) { RisorsaIncapsulata r = new RisorsaIncapsulata("R"+(i+1)); pool.add(r); } } /** * Alloca una risorsa se disponibile. * Usa il pattern Singleton per allocare se stesso la prima volta * e rendersi univoco. * @param owner stringa che identifica il proprietario della risorsa * @return una risorsa, se disponibile, null altrimenti */ public static Risorsa getInstance(String owner) { if (instance == null) instance = new GestoreRisorse(); Iterator it = pool.iterator(); while (it.hasNext()) { RisorsaIncapsulata ri= (RisorsaIncapsulata)it.next(); if (ri.isAssigned() == false) { ri.assign(owner); return ri.getRisorsa(); } } return null; // non c'erano risorse disponibili // in alternativa qui potrei aggiungere una nuova risorsa all'array // e restituire quella. } /** Rilascia una risorsa. * Usa il pattern Singleton. * @param r risorsa da rilasciare */ public static void releaseInstance(Risorsa r) { if (instance == null) instance = new GestoreRisorse(); Iterator it = pool.iterator(); while (it.hasNext()) { RisorsaIncapsulata ri = (RisorsaIncapsulata)it.next(); if (r == ri.getRisorsa()) { ri.free(); return; // ho finito; se fossero troppe potrei diminuirle... } } } /** Stampa lo stato del GestoreRisorse */ public static void print() { System.out.print("\nStato del Gestore delle Risorse: "); System.out.println("sono gestite "+pool.size()+" risorse"); Iterator it = pool.iterator(); while (it.hasNext()) { RisorsaIncapsulata ri = (RisorsaIncapsulata)it.next(); System.out.println(ri.status()); } System.out.println(""); } /** Classe che ingloba la risorsa di cui si vogliono gestire n istanze */ private class RisorsaIncapsulata { private Risorsa risorsa; // la risorsa da gestire private boolean assigned; // true se la risorsa e' data a qualcuno private String owner; // possessore della risorsa public RisorsaIncapsulata(String name){ risorsa = new Risorsa(name); assigned = false; owner = null; } /** Assegna la risorsa, se libera, a qualcuno * @param owner chi richiede la risorsa * @return true se la risorsa e' stata assegnata, false se gia' in uso Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 55 - LF Java Handbook */ public boolean assign(String owner){ if (assigned == true) return false; this.owner = owner; assigned = true; return true; } /** Libera la risorsa */ public void free(){ assigned = false; } /** Indica se la risorsa e' gia' assegnata a qualcuno * @return true se la risorsa e' assegnata */ public boolean isAssigned(){ return assigned; } /** Stato della risorsa * @return stato della risorsa in formato stringa comprensibile */ public String status(){ return ("Risorsa " + risorsa.getName() + (assigned?" assegnata a "+owner+".":" disponibile.")); } /** Risorsa vera e propria * @return la risorsa */ public Risorsa getRisorsa() { return risorsa; } } } src/GestoreRisorse/PackageRisorse/Risorsa.java package PackageRisorse; /** * Generica risorsa di cui si vogliono gestire n istanze * Potrebbe essere una connessione ad un database, una connessione a delle * linee di trasmissione, un'area di memoria etc. * @author L. Ferrari * @version 1.0 del 31.1.2004 */ public class Risorsa { private String name; // nome della risorsa /** * Costruttore: e' protected in modo che solo le classi del package * (e in particolare il pool manager) possano accedervi. */ protected Risorsa(String name){ this.name = name; } // possono essere definiti quanti metodi si vogliono /** Nome della risorsa * @return nome */ public String getName(){ return name; } } 13.2. SenderArgument Scopo: fare in modo che un oggetto su cui e' chiamato un metodo possa agire sull'oggetto chiamante. Riferimenti: http://patterndigest.com/patterns/SenderArgument.html . Soluzione: si passa un riferimento all'oggetto corrente utilizzando la parola chiave this: unOggetto.faQualcosa(this); Note: utilizzato quando e' necessario che il ricevitore conosca chi e' il mittente, utilizzato nel pattern Observer e nel pattern Relationship Object. 13.3. Iteratore - 56 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Scopo: consentire un metodo di esplorazione di collezioni implementazione reale. Si dichiara come classe interna di una classe. Esempi di uso: • vedi il capitolo di "StringTokenizer" nel capitolo relativo alle stringhe. indipendente dalla • vedi il capitolo di "Strutture dati astratte". • vedi il capitolo di "Collezione di oggetti". 13.4. Observer E' un pattern comportamentale. Scopo: disaccoppiare il piu' possibile le diverse parti di una applicazione adibite al controllo, all'accesso ai dati e alla presentazione. Spesso il controller e' un listener. Riferimenti: Mokabyte n.70, Gennaio 2003 (troppo complesso in alcune parti). 13.4.1. Realizzazione tramite Observer-Observable Sono classi di java.util. Questo modello a' meno utilizzato del successivo che usa i JavaBeans, perche' una delle classi deve estendere Observable e ci possono essere problemi se si deve ereditare gia' da un'altra classe. Esempio di uso: sudoku. Il pattern e' utilizzato nella mia realizzazione di sudoku per consentire alle classi piu' interne di propagare il loro cambiamento di stato a quelle che le usano, qualora l'oggetto della classe piu' interna (una cella) sia condiviso da piu' oggetti della classe piu' esterna (insiemi di nove celle che le condividono). Esempio di pattern Observer realizzato tramite classi observer-observable. 13.4.2. Realizzazione tramite JavaBean E' un modello a componenti. Uno dei principali obiettivi e' quello di realizzare un basso accoppiamento tra soggetto osservato e osservatori. Il soggetto osservato non sa nulla dell'osservatore o degli osservatori (che vengono chiamati listener in questo modello). E' possibile utilizzare delle classi anonime per implementare l'interfaccia ActionListener nel - 57 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook soggetto da osservare. Esempio tratto da Object Oriented Design and Patterns, p.160. unBottone.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent evento) { // qui ci va quello che deve essere fatto quando il bottone viene premuto unTextField.setText("Bottone premuto"); } }); Esempio tratto da Object Oriented Design and Patterns, cap. 4. (src/TimerTester.java) package ch4.timer; import import import import import java.awt.*; java.awt.event.*; java.util.*; javax.swing.*; javax.swing.Timer; /** This program shows a clock that is updated once per second. */ public class TimerTester { public static void main(String[] args) { JFrame frame = new JFrame(); final int FIELD_WIDTH = 20; final JTextField textField = new JTextField(FIELD_WIDTH); frame.getContentPane().setLayout(new FlowLayout()); frame.getContentPane().add(textField); ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent event) { Date now = new Date(); textField.setText(now.toString()); } }; final int DELAY = 1000; // Milliseconds between timer ticks Timer t = new Timer(DELAY, listener); t.start(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } } TimerTester in azione. TO DO: Non e' ancora chiaro come sia possibile utilizzare il metodo dei JavaBean con classi qualunque come soggetti da osservare. Probabilmente e' sufficiente che implementino qualche interfaccia... 13.4.3. Applicazione di Observer: pattern MVC (Model View Controller) Si dividono le responsabilita' in tre: • Model: si occupa della rappresentazione dei dati della applicazione; deve modificare lo - 58 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook stato a seguito di richieste effettuate dall'utente tramite il controller; deve notificare i cambiamenti del proprio stato alla o alle viste del modello (pattern Observer). Non conosce nulla dei suoi controller e delle sue view. • View: e' la vista (interfaccia utente) del modello: per ogni modello possono esserci piu' viste; invia al controller eventuali richieste dell'utente. Interagisce con il model tramite un riferimento ad esso. • Controller (o listener): interpreta le richieste della view (input dell'utente) e le trasforma in azioni che vanno a modificare il model o che cambiano la view. Interagisce con il model tramite un riferimento ad esso. Vantaggi: • c'e' una netta separazione tra i componenti del programma che possono essere sviluppati in meniera indipendente • il collegamento tra modello e view e tra modello e listener avviene a runtime. Esempio di pattern MVC: bottone che cambia colore mentre e' tenuto premuto: • Model: = attributo che contiene il codice del colore. • View: = colorazione del bottone sul video. • Controller: = modulo di gestione dell'evento pressione. 13.4.4. Java Message Service (JMS) E' un altro esempio di implementazione del pattern Observer; consente a un numero indefinito di sottoscrittori di essere avvisati a seconda del tipo di messaggio che e' stato generato e per cui si sono registrati. 13.4.5. Problemi del pattern Observer • L'oggetto osservato non sa nulla degli Osservatori (listener) per cui per il garbage collector non e' possibile rimuoverli prima che sia stato rimosso l'oggetto osservato. • Non e' garantito l'ordine con cui vengono "svegliati" i listener. Se si vuole una notifica a "cascata" interporre classi in mezzo che realizzino l'ordine. 13.5. Command Ne esistono almeno due versioni. 13.5.1. Insieme di comandi che producono output diversi (es. gitelf) Consente di produrre piu' output da uno stesso input. E' possibile aggiungere nuovi formati di uscita senza modificare la classe che esegue il parsing dell'input. Le classi sono: • Interfaccia <output>Builder: prevede una serie di metodi, uno per ogni possibile comando trovato nell'input. • Una o piu' classi che implementano l'interfaccia <output>Builder in concreto • Director: il costruttore ha in input un ouputBuilder; esegue il parsing dell'input e per ogni comando trovato chiama il metodo sull'oggetto OutputBuilder. • Lancio: e' la classe che crea piu' oggetti Director, uno per ogni output, passando a ciascuno il giusto oggetto che implementa <output>Builder. Come si procede: • si individuano i comandi da processare; - 59 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook • si scrive l'interfaccia <Output>Builder; • si realizza il parser che individua i comandi e li applica a oggetti di tipo <output>Builder; • si realizzano le classi che producono l'output; • si scrive la classe Lancio. Se servono piu' output si crea un nuovo oggetto di tipo <output>Builder e un nuovo director. Svantaggi: Il parsing viene effettuato una volta per ogni output. Verificare la possibilita' di utilizzare insieme il pattern observer per evitare questo problema. 13.5.2. Comando che deve essere lanciato da piu' fonti: Action Riferimenti: ad es. Horstmann, ObjectOriented Design and Patterns, p.399. Il pattern command e' utilizzato in Swing per consentire di eseguire un comando da diverse fonti di input, ma puo' essere utilizzato in altri casi. Il comando puo' avere anche uno stato oltre che dei comportamenti. Si utilizza l'interfaccia Action che corrisponde ad un comando. E' possibile poi utilizzare il metodo actionPerformed() per lanciarlo. Stato: come esempi di stato ci possono essere il fatto di essere abilitato o meno, il nome, una icona, etc. L'abilitazione o la disabilitazione viene fatta in Swing con setEnabled() mentre le altre proprieta' possono essere settate utilizzando le costanti del tipo Action. Esempio di applicazione del pattern Command con Action (src/GUISeparataTest.java) import java.awt.*; import java.awt.event.*; import javax.swing.*; - 60 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook /** * <p>Title: GUISeparataTest </p> * <p>Description: Interfaccia grafica separata dalla gestione degli eventi.</p> * <p>Copyright: Copyright (c) Luigi Ferrari, 2002</p> * <p>Company: Luigi Ferrari</p> * @author Luigi Ferrari, [email protected] * @version 1.0 */ /** Azioni logiche: colorare lo sfondo della form */ class ColorAction extends AbstractAction { private Component target; public ColorAction(String name, Icon icon, Color c, Component comp) { putValue(Action.NAME,name); putValue(Action.SMALL_ICON, icon); putValue("Color", c); target = comp; } public void actionPerformed(ActionEvent evt) { Color c = (Color)getValue("Color"); target.setBackground(c); target.repaint(); } } /** definizione di bottoni in base a delle azioni logiche * ne basta una perche' le azioni sono le stesse */ class ActionButton extends JButton { public ActionButton(Action a) { setText((String)a.getValue(Action.NAME)); Icon icon = (Icon)a.getValue(Action.SMALL_ICON); if (icon != null) setIcon(icon); addActionListener(a); } } /* Interfaccia utente */ class GUISeparata extends JFrame { public GUISeparata() { /* aspetto generale della form */ setTitle("Esempio di Interfaccia Utente separata dalle azioni"); setSize(300,200); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0);} }); JPanel panel = new JPanel(); /* definizione delle azioni logiche */ ColorAction blueAction = new ColorAction ("Blue", new ImageIcon("blue_ball.gif"), Color.blue, panel); ColorAction yellowAction = new ColorAction ("Yellow", new ImageIcon("yellow_ball.gif"), Color.yellow, panel); ColorAction redAction = new ColorAction ("Red", new ImageIcon("red_ball.gif"), Color.red, panel); /* associazione dei pulsanti alle azioni logiche */ panel.add(new ActionButton(yellowAction)); panel.add(new ActionButton(redAction)); panel.add(new ActionButton(blueAction)); /* associazione dei tasti della tastiera alle azioni logiche */ panel.registerKeyboardAction(yellowAction, KeyStroke.getKeyStroke(KeyEvent.VK_Y,0), JComponent.WHEN_IN_FOCUSED_WINDOW); panel.registerKeyboardAction(redAction, KeyStroke.getKeyStroke(KeyEvent.VK_R,0), JComponent.WHEN_IN_FOCUSED_WINDOW); panel.registerKeyboardAction(blueAction, KeyStroke.getKeyStroke(KeyEvent.VK_B,0), JComponent.WHEN_IN_FOCUSED_WINDOW); /* inizializzazione sfondo */ Container contentPane = getContentPane(); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 61 - LF Java Handbook panel.setBackground(Color.white); contentPane.add(panel); /* associazione di voci di menu' alle azioni logiche */ JMenu m = new JMenu("Color"); m.add(yellowAction); m.add(blueAction); m.add(redAction); JMenuBar mbar = new JMenuBar(); mbar.add(m); setJMenuBar(mbar); } } public class GUISeparataTest { public static void main(String[] args) { JFrame f = new GUISeparata(); f.pack(); // ATTENZIONE: serve se non ho specificato le // dimensioni di base per adattare la finestra ai // componenti che ci sono dentro. f.show(); } } 13.6. Proxy Vedi anche Argomenti avanzati - riflessione. 13.7. Facade Lo scopo e' nascondere la realizzazione di un comportamento utilizzando un classe che espone l'interfaccia. Sotto la classe puo' esserci addirittura piu' di una classe, ad esempio per rendere persistenti degli oggetti. Puo' essere utilizzato per disaccoppiare parti di sistema fornendo una interfaccia di alto livello che utilizza i metodi delle classi nascoste per realizzare il comportamento voluto. E' utilizzato ad esempio nei javabean (v). - 62 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 14. Esempi di Object Oriented Design 14.1. Forza 4 Il gioco Forza 4 con architettura client-server. Non e' stato ancora implementato. L'immagine e' stata realizzata con Violet di Horstmann. - 63 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 15. APPLICAZIONI ENTERPRISE 15.1. Servlet Sono eseguite sul server remoto. In pratica una servlet e' una API utilizzata dal Web Server per fornire nuovi servizi. Di solito non hanno alcuna interfaccia grafica. Vengono attivate una volta solo alla attivazione del Server, possono ricordare lo stato. Inoltre possono comunicare tra loro anche attraverso pipeline. Per programmare utilizzando le servlet non basta il normale java sdk, serve la versione enterprise. ATTENZIONE: sembra invece che basti il normale sdk integrato con il file servlet.jar, che deve essere messo nella dir jre\lib\ext del jdk oppure aggiunto a CLASSPATH. 15.1.1. Esempio di servlet Attenzione: codice non provato ma compilato (sapilf/java/testservlet). File ProvaServlet.java import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ProvaServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { PrintWriter out = res.getWriter(); out.println("Servlet di prova"); } } Dopo la compilazione con j2ee deve essere messo sotto httpd/servlet. Per lanciarlo sul browser selezionare http://host/servlet/ProvaServlet 15.2. JavaBean Riferimento: Horstmann, Object Oriented design and patterns. Un javabean e' un sistema di una o piu' classi che realizza uno scopo. Spesso e' utilizzato nelle applicazioni enterprise per incapsulare i dati che sono resi persistenti in modo trasparente. E' contraddistinto da: • attributi come le classi normali. • metodi getter e setter: possono non esserci tutti, possono fare delle operazioni complesse, come ad esempio occuparsi della persistenza, ad esempio prendendo e scrivendo i dati in un database. • puo' generare eventi. La sua interfaccia e' di solito realizzata con una singola classe facade (secondo il pattern facade) che nasconde la struttura interna, composta anche da piu' classi. 15.2.1. Creazione di un file jar con il javabean Occorre creare un manifesto che esponga la classe facade. Vedi libro. 15.2.2. Loading di un javabean in un IDE Vedi libro. - 64 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 16. JDBC - JAVA E I DATABASE 16.1. Connessione e disconnesione dal database Nell'esempio si fa riferimento a database Oracle. /* Costanti */ private static final String dbUser private static final String dbPassword /* Variabili */ private static Connection private static boolean public static String public static String = "user"; = "password"; dbConnection; dbIsConnected = false; dbSid = "theSID"; dbServerAddr = "hostname"; // "192.168.123.18"; /* it make takes time... */ public static final Connection dbGetConnection() throws SQLException, java.lang.InterruptedException { if (dbIsConnected) return dbConnection; DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); dbConnection = DriverManager.getConnection( "jdbc:oracle:thin:@" + dbServerAddr + ":1521:" + dbSid, dbUser,dbPassword); dbIsConnected = true; System.out.println ("dbGetConnection: connected."); return dbConnection; } public static final void dbCloseConnection () { try { if (dbIsConnected) { dbConnection.close(); System.out.println ("dbCloseConnection: disconnected."); dbIsConnected = false; } } catch ( SQLException e ) { System.out.println ("dbCloseConnection: " + e); } } Sono utili anche delle funzioni locali che aprono e chiudono la connessione e creano uno statement in un unico colpo: private Statement createStatement() { Statement stmt=null; Connection conn; try { // Open connection & statement conn = dbGetConnection(); return conn.createStatement(); } catch ( Exception e ) { e.printStackTrace(e); return null; } } private void destroyStatement(Statement stmt) { try { //Close connection & statement stmt.close(); dbCloseConnection(); } catch ( Exception e) { e.printStackTrace(e); } } 16.2. Select - 65 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Select con cursore String query = "select cod, dsc " + " from database.tabella " + " where cod < " + valminimo + " database.tabella order by cod"; Statement stmt = createStatement(); try { ResultSet rs = stmt.executeQuery(query); while (rs.next()){ System.out.println("Read: cod="+ rs.getString(1) + " description: " + rs.getString(2)); } } catch (Exception e) { System.out.println("ERROR: query is: "+query); // Proseguo con la chiusura del db senza lancio di eventuali exception Sapi.dbCloseConnection(); return; } destroyStatement(stmt); 16.3. Chiamata di stored procedure private long chiamataDiStroredProcedure(long par1, long par2) { int reply=0; Connection conn; try { conn = dbGetConnection(); } catch ( Exception e ) { e.printStackTrace(); return 0; } try { CallableStatement stm = conn.prepareCall("{? = call db.xxx(?,?,?,?)}"); stm.registerOutParameter(1, java.sql.Types.TINYINT); //reply stm.setLong(2, par1); // parametro 1 (input) stm.setLong(3, par2); // parametro 2 (input) stm.registerOutParameter(4, java.sql.Types.INTEGER); // out 1 stm.registerOutParameter(5, java.sql.Types.INTEGER); // out 2 ResultSet rs = stm.executeQuery(); rs.next(); reply = stm.getInt(1); if (reply != 0) { jStatusBar.setText("ERROR: Stored procedure xxx failed. "R); return -1; } return stm.getInt(4); } catch (SQLException e) { e.printStackTrace(e); return -1; } } 16.4. Insert e delete Da fare 16.5. Istruzioni DDL Da fare - 66 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 17. DATABASE SERVER HSQLDB Scaricato da internet, www.hsqldb.org, versione installata: 1.7.1. E' gratuito. I dati sono salvati in chiaro come comandi sql. Sono disponibili diverse versioni del database: • in memoria • stand alone (un singolo programma che lo usa) • server: piu' programmi possono accedere insieme al database. • webserver: non ancora provata. 17.1. Installazione Si scompatta il file dato in una dir qualunque, quello che importa e' che la libreria sia accessibile. E' possibile ricostruire la libreria per la versione jdk che si usa. 17.2. Utility 17.2.1. DatabaseManager consente di operare sul database tramite SQL: @java -cp [DIR_DELLA_LIB]\hsqldb.jar org.hsqldb.Server -database nomedb 17.2.2. ScriptTool lancia uno script sul database: @java -cp [DIR_DELLA_LIB]\hsqldb.jar org.hsqldb.util.ScriptTool -database nomedb -script nomescript -log true >> file_di_log 17.3. Versione server Operazioni da effettuare: - creare il database con ScriptTool creare un file che lanci il server provare ad accedere al database tramite DatabaseManager scrivere un programma java che accede al database. 17.4. Organizzazione delle dir Rispetto alla dir del progetto: bin contiene gli script per la gestione builddb.bat runserver.bat runmanager.bat Eventualmente creare dei collegamenti per poterli lanciare da Windows. data contiene il database: nomedatabase.properties nomedatabase.script ddl contiene gli script per la creazione del database da zero NB: uso LF_HOME come dir di partenza, nella sottodir lib ho messo hsqldb.jar - 67 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 17.4.1. Esempio di script per la creazione di un database /bin/builddb.bat echo off; echo echo Creazione database... set LF_HOME=e:/dellusers/luigi Copyright Luigi Ferrari, 2003 cd ..\data @java -classpath %LF_HOME%\lib\hsqldb.jar org.hsqldb.util.ScriptTool -database nomedb -script ..\ddl\tableddl.sql -log true >..\log\b.log echo Caricamento Look-up tables... @java -cp %LF_HOME%\lib\hsqldb.jar org.hsqldb.util.ScriptTool -database nomedb -script ..\ddl\lutdata.sql -log true >>..\log\b.log echo Caricamento dati di test... @java -classpath %LF_HOME%\lib\hsqldb.jar org.hsqldb.util.ScriptTool -database nomedb -script ..\ddl\testdata.sql -log true >>..\log\b.log echo Database creato. cd ..\bin dove ad esempio il file ddl/tableddl.sql e' fatto da statement Sql; per i commenti si usa una doppia lineetta iniziale: File: ddl/tabledd.sql -- File name: nomedb.sql -- Author: Luigi Ferrari -- Copyright: Luigi Ferrari - [email protected] -- Version: 1.0 del 21.3.3 -- tables drop drop table Table1 if exists; go -- Tables CREATE TABLE Table1 ( codice CHAR NOT NULL primary key, descrizione VARCHAR(30) ); go 17.4.2. Esempio di avvio del server ATTENZIONE: nella dir di lancio deve essere presente il file server.properties che contiene la posizione del database rispetto alla directory di lancio. Ad esempio, se lo lancio dalla dir bin e il database e' nella dir data: File server.properties server.database=../data/nomedatabase Se il nome del database contiene il nome del nodo ed e' in una cartella condivisa dovrebbe essere accessibile anche dalla rete (da verificare). File: bin/runserver.bat set echo off echo Copyright Luigi Ferrari, 2003 echo Lancia il server del database... echo Il nome del database e' preso dal file server.properties @java -cp %LF_HOME%/lib/hsqldb.jar org.hsqldb.Server 17.4.3. Esempio di avvio del manager del database in versione standalone e server - 68 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook NOTA: Se e' lanciato per la versione server il server deve essere gia' stato attivato (runserver) e non serve il nome del database (basta l'indicazione //localhost) File: bin/runmanager.bat echo off; echo echo Manager del database... Copyright Luigi Ferrari, 2003 rem versione stand alone: rem @java -cp %LF_HOME%\lib\hsqldb.jar org.hsqldb.util.DatabaseManager -url jdbc:hsqldb://W11/w11-d/users/luigi/projects/GiteLF/data/gite rem versione con server @java -cp %LF_HOME%\lib\hsqldb.jar org.hsqldb.util.DatabaseManager -url jdbc:hsqldb:hsql://localhost 17.4.4. Esempio per vedere il contenuto del database ATTENZIONE: e' da mettere a posto, mi sembra che non funzioni. echo off; echo Copyright Luigi Ferrari, 2003 echo Show data... set LIB=%LF_HOME%\lib cd ..\data @java -cp %LF_HOME%\lib\hsqldb.jar org.hsqldb.util.ScriptTool -database nomedb -script ..\ddl\show.sql -log true >..\log\s.log echo ... echo Data wrote into ../log/s.log echo File view: edit ..\log\s.log exit - 69 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 18. TIPS: Soluzione di problemi 18.1. Standard main - DA RISOLVERE Deve avere le seguenti funzionalita' • gestione argc argv (o parametri della applet in alternativa) • gestione opzioni • usage • copyright • log • equivalente del c per uscire in caso di errore Vedere il capitolo main sotto programmazione.gpp per la conversione dei parametri in liste. 18.2. log - DA FARE Vedere GiteXML, dovrebbe gia' essere fatto. NB da Java 1.4 esistono le API apposite. Mettere qui esempio pratico. 18.3. Out Of Memory Se un programma va in out of memory e' possibile incrementare la dimensione massima dell'heap rispetto alla simensione standard di 64 MB, portandola ad esempio a 256MB: java -Xmx256m -cp ... ClasseMain.class java -Xmx256m -jar /home/cay/web/com/violet/violet.jar (Kay Hortsmann, manuale d'uso del programma Violet per il disegno di diagrammi UML). 18.4. Attributi che devono contenere valuta Non e' mai una buona scelta utilizzare i valori double: conviene invece usilizzare gli interi o i BigInteger prendendo come unita' di misura la piu' piccola frazione della valuta in questione e facendo la conversione al momento della acquisizione e della stampa (da Kay Horstmann, Object Oriented Design and Patterns", Wiley internation Edition). 18.5. Variabili che cambiano valore tra una chiamata e l'altra Se un record di una variabile Vector non mantiene il proprio valore ma lo cambia ad ogni aggiunta di un nuovo record significa che e' stata definita static (cioe' e' una variabile di classe e non di istanza) 18.6. Check su variabile booleana restituita come oggetto if (((Boolean)config.get("DEBUG")).booleanValue()) 18.7. NullPointerException potrebbe essere una variabile della classe che non e' stata inizializzata nel costruttore (ad esempio e' stata creata nel main come variabile separata) 18.8. Stampa con Java - DA RISOLVERE Esiste articolo da provare. Esiste un progetto su sorgeforce.net GFP che lo risolve. Scaricato e messo provvisoriamente - 70 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook su Dell85000//D:/tmp 18.9. Pulizia della memoria (garbace collection forzata) Si ottiene con la chiamata: System.gc(); 18.10. Calcolo del tempo di elaborazione prima: System.gc(); long startTime=System.currentTimeMillis(); dopo: System.out.println("Completed in: " + (System.currentTimeMillis()-startTime)); 18.11. Controllo delle versione della JRE in esecuzione String vers = System.getProperty("java.version"); if (!vers.equals("1.4.0_01")) { // da migliorare... ... } 18.12. Appleviewer non visualizza applet per problemi con X Appletviewer fallisce dicendo: impossibile al server invalid DISPLAY localhost:0.0 Soluzione: da una finestra come user root dare xhost + 18.13. Netscape su Linux: visualizzazione di applet Netscape all'apertura di una applet dice "JavaFormatError Bad Major Version Number" Soluzione: ? Potrebbe essere un problema di difficile soluzione perche JRE 2 plug-in, secondo la doc su W13, non va con Nescape 4. 18.14. Errori di arrotondamento Non esiste 4.35, viene memorizzato come 4.349999999... double f =4.35; int n = (int)(100 * f); System.out.println(n); // stampa 434!!! Usare invece: int n = i(int)Math.round(100*f); // 435 18.15. Conversione decimale-binario In Java esiste il metodo statico toString Integer.toString(n, 2) Integer.parseInt(digitString, 2); 10 -> 2 2 -> 10 - 71 - Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook La base deve essere compresa tra 0 e 36. 18.16. Permissions sulle applet Si verifica con Applet shipgate. • si riesce a far girare con la connessione remota (cioe' con classe su PC con Windows che si collega a DB oracle su Linux) solo da Jbuilder: e' un problema di permissions: Provato senza successo a copiare il file c:\programmi\JBuilder7\jdk1.3\jre\lib\security\java.policy che ha le permission a ALL, sotto c:\programmi\java\j2re1.4.0_01\bin Ho anche avviato il tool javapolicy (sempre sotto bin), e riavviato il PC • si riesce a far partire da Windows 98 con tutto sul server dopo aver trasferito anche tutte le librerie necessarie (alcune delle quali sono di Oracle e alcune di Jbuilder). • Client nome SAPI, Host SAPI 18.17. Random - Generazione di comportamenti casuali Random randomGenerator; randomGenerator = new Random(); int index = randomGenerator.nextInt(); int indexMinoreDi = randomGenerator.nextInt(max); (0 : max-1) int indexLimitato = randomGenerator.nextInt(min, max+1); (min : max) long unLong = randomgenerator.nextLong(); 18.18. Date and Time - Visualizzazione data corrente public class MyClass { SimpleTimeZone gdt; SimpleDateFormat sdf; Date currentTime; public MyClass() { gdt = new SimpleTimeZone(0, "GMT"); // forse inutile sdf = new SimpleDateFormat("hh:mm:ss"); currentTime = new Date(); } public String update() { currentTime.setTime(System.currentTimeMillis()); return sdf.format(currentTime); } } 18.19. Date and Time - Classi standard Dalla versione 1.1 a java.util.Date sono state aggiunte java.util.Calendar (la sua sottoclasse da utilizzare e' java.util.GregorianCalendar) e java.util.DateFormat. GregorianCalendar ha anche alcuni metodi utili tra cui before(GregorianCalendar) e after(GregorianCalendar), booleani, che consentono il confronto tra due date. // ECT: European Central Time GregorianCalendar d = new GregorianCalendar(TimeZone.getTimeZone("ECT")); d.setTime(new Date()); // d contiene la data corrente // mette l'ora a mezzanotte: d.set(Calendar.HOUR_OF_DAY, 24); d.set(Calendar.MINUTE, 0); d.set(Calendar.SECOND, 0); d.set(Calendar.MILLISECOND, 0); int day = d.get(Calendar.DAY_OF_MONTH); int month = d.get(Calendar.MONTH) + 1; - 72 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook ATTENZIONE: per estrarre il mese corrente fare attenzione al +1 (si parte da 0). 18.20. Problemi con piu' finestre Ricordarsi di mettere System.exit(0) quando si usano finestre pop-up eccetera perche' sono lanciate come thread separati e potrebbero sopravvivere al processo padre. Cosa Succede nel caso delle applet? 18.21. Configurazione di una applicazione. Utilizzare il package java.util.prefs.Preferences. Consente di memorizzare due livelli di parametri di configurazione, uno di sistema e uno per ogni utente. La memorizzazione avviene in modo dipendente dal sistema operativo ma trasparente per il programmatore. Le preferenze fanno riferimento alla classe (o package) passato. Per l'uso vedere Core Java Technologies Tech Tips del 15 Luglio 2003 e la documentazione della classe java.util.prefs.Preferences. ALTERNATIVA: Esiste una mia api ConfigFile (vedi api.gpp) che consente di gestire i file di configurazione della forma Nome=Valore. Il problema e' comunque quello di far conoscere il nome del file a tutte le classi. Soluzione adottata nel progetto jpp: • Creata una classe con le costanti della applicazione, fra cui il nome della stessa, la versione e il nome del o dei file di configurazione. Essa contiene anche un oggetto di tipo ConfigFile statico (unico cosi' per tutta la applicazione); meglio sarebbe stato implementare il singleton in ConfigFile. • Una delle classi della applicazione conosce la posizione assoluta del file (ma a quel punto potrebbe anche conoscerne il nome) e carica nell'oggetto ConfigFile la configurazione corrente. • Nelle classi che devono utilizzare i parametri di configurazione si prendeno con la chiamata <classeCostanti>.<oggettoConfigFile>.getValue(key) VEDERE ANCHE: • progetto ccsapicc per la configurazione dei singoli processi 18.22. Associazione di un programma java al tipo di un file sotto Windows Scopo e' quello di poter chiamare un programma java direttamente dal tasto destro del mouse sul file. Soluzione adottata in jpp: • si crea una classe che accetta il nome di un file come argomento (i.e. JppStandAlone) • si crea un file .bat che lancia il programma (vedi listing) • si installa il file in un dir opportuna di installazione facendo in modo che tutti i riferimenti a file di configurazione o altri input siano definiti con percorso assoluto. • con tasto destro del mouse di sceglie Apri con.. e sfogliando si cerca il file bat. Esempio di file batch (jppexe.bat) NB: La riga di lancio del file java e' tutta su una riga. echo off set LF_HOME=c:\Programmi\LF\jpp @java -cp "%LF_HOME%/avalon-framework-cvs-20020806.jar;%LF_HOME%/xml-apis.jar; %LF_HOME%/batik.jar;%LF_HOME%/xalan-2.4.1.jar;%LF_HOME%/xercesImpl-2.2.1.jar; %LF_HOME%/fop.jar;%LF_HOME%/lfapi.jar;%LF_HOME%/jpp.jar" JppStandAlone %1 if ERRORLEVEL goto err 0 goto ok - 73 - Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook :err echo "jpp: ...errore durante l'esecuzione" goto done :ok echo "jpp: %1: xml and pdf created." :done pause 18.23. Creazione di un link per un programma java Esempio di file batch (lancio di jpp a finestra) Attenzione ai file di configurazione che devono essere installati nelle dir corrette. ECHO Jpp: gpp (xml) to pdf converter @java -cp "avalon-framework-cvs-20020806.jar;xml-apis.jar;batik.jar;xalan-2.4.1.jar; xercesImpl-2.2.1.jar;fop.jar;lfapi.jar;jpp.jar" Jpp Si crea poi un collegamento a questo file, nelle proprieta' si associa un'icona. 18.24. Organizzazione di una applicazione in librerie Esempio: bluej bluej.jar: • bluej\Boot.java • bluej\Splash.java • bluej\Splash.jpg bluejcore.jar: • bluej/ • bluej/classmgr/ • bluej/compiler/ • bluej/graph/ • ... • bluej/utility/ • bluej/utility/filefilter/ • bluej/views/ • bluej/BlueJEvent.class • bluej/BlueJEventListener.class • bluej/BlueJTheme.class • ... • bluej/utility/Queue.class • bluej/utility/SortedProperties.class • bluej/utility/Utility.class$list() bluej/utility/ • ... - 74 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 19. ALGORITMI 19.1. Strutture dati astratte src/ListaCollegata.java package StruttureDatiAstratte; import java.util.NoSuchElementException; /** * ListaCollegata e' una versione semplificata della classe * java.util.LinkedList che implementa una lista linkata doppia con * i seguenti metodi (non sono gli unici): * void addFirst(Object obj) * void addLast(Object obj) * Object getFirst() * Object getLast() * Object removeLast() * Object removeFirst() * Inoltre dispone di un iteratore listIterator che consente di esplorare * la lista a piacimento tramite i metodi * Object next() sposta l'iteratore in avanti (attenzione, solleva eccezione * NoSuchElementException se e' alla fine della lista) restituendo * l'oggetto estratto * boolean hasNext() * Object Previous() * boolean hasPrevious() * void add(Object) aggiunge un oggetto nella posizione corrente * void remove() elimina l'oggetto nella posizione corrente * Esempio di uso della classe LinkedList: * LinkedList list = ...; * ListIterator iterator = list.ListIterator(); * ... * while (iterator.hasnext()) { * Object obj = iterator.next(); * // usa obj... * if (obj ... non va bene) * iterator.remove(); * iterator.next(); * Object o = new Object(...); * iterator.add(o); * } * @author L.Ferrari * @version 1.0 del 24.3.2003 */ public class ListaCollegata { /** Classe interna privata, non viene restituita da alcun metodo della * classe esterna pubblica */ private class Elemento { public Object dato; public Elemento next; } // Classe pubblica private Elemento primo; /** Costruttore */ public ListaCollegata() { primo = null; } /** restiuisce il primo elemento della lista */ public Object getTesta() { if (primo == null) throw new NoSuchElementException(); return primo.dato; } /** inserisce in testa */ public void addTesta(Object obj) { Elemento nuovo = new Elemento(); nuovo.dato = obj; nuovo.next = primo; primo = nuovo; } /** toglie dalla testa restituendo l'oggetto rimosso */ Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 75 - LF Java Handbook public Object removeTesta() { if (primo == null) throw new NoSuchElementException(); Object obj= primo.dato; primo=primo.next; return obj; } /** crea un iteratore per la lista */ public Iteratore listIterator() { return new Iteratore(); } /** definisce un iteratore sulla lista. * E' una classe interna ma pubblica, per accedervi occorre farvi * riferimento come ListaCollegata.Iteratore * Il concetto di iteratore e' un pattern. */ public class Iteratore { public Elemento corrente; public Elemento precedente; public Iteratore() { corrente = null; precedente = null; } public Object next() { if (corrente == null) { corrente = primo; return getTesta(); } else { if (corrente.next == null) throw new NoSuchElementException(); precedente = corrente; // serve per remove corrente = corrente.next; return corrente.dato; } } public boolean hasNext() { if (corrente == null) // iteratore appena creato: return primo != null; // esiste next se lista non e' vuota // altrimenti next esiste se lista non finita return corrente.next != null; } public void add(Object oggetto) { if (corrente == null) addTesta(oggetto); Elemento nuovo = new Elemento(); nuovo.dato = oggetto; nuovo.next = corrente.next; corrente.next = nuovo; corrente = nuovo; precedente = null; } /** in base alla definizione di remove non e' permesso chiamare due * volte di seguito remove (non si saprebbe come recuperare il * precedente del precedente) */ public void remove() { if (corrente == primo) removeTesta(); else { if (precedente == null) throw new IllegalStateException(); precedente.next=corrente.next; corrente=precedente; } precedente = null; } } public static void main (String[] args) { ListaCollegata lista = new ListaCollegata(); lista.addTesta("Ernesto"); lista.addTesta("Clara"); lista.addTesta("Davide"); lista.addTesta("Mario"); ListaCollegata.Iteratore it = lista.listIterator(); it.next(); // M|DCE it.next(); // MD|CE it.add("Giuseppe"); // MDG|CE it.add("Felicina"); // MDGF|CE it.next(); // MDGFC|E it.remove(); // MDGF|E // stampa tutti gli elementi Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 76 - LF Java Handbook it = lista.listIterator(); while(it.hasNext()) System.out.println(it.next()); } } 19.2. Algoritmi matematici 19.2.1. Potenza n-esima di numero reale (metodo degli invarianti di ciclo) Alternativa alla moltiplicazione n volte di a: si utilizza il metodo degli Invarianti di ciclo: algoritmo (equivale a Math.pow (a, n)) double a=...; int n=...; double r = 1; double b = a; int i = n; while (i > 0) { if ( i%2 == 0) { b = b * b; i = i / 2; } else { r = r * b; i--; } } //risultato in r, che vale a^n Esempio: se n= 100 fa tutto utilizzando 10 moltiplicazioni anziche' 100. Cenni di dimostrazione: • All'inizio del ciclo while vale la relazione r * b^i = a^n • Per ogni ciclo, questa relazione e' sempre verificata, solo che via via cresce r e diminuisce b^i. • Alla fine il termine b^i diventa b^0, cioe' 1, e r contiene il risultato! 19.2.2. Calcolo della radice quadrata Preso da C. Horstmann, Debug_Java2.pdf. Si usa il metodo delle approssimazioni successive, conosciuto gia' ai tempi degli antichi greci. Si deve trovare sqrt(a). Si parte da un valore di tentativo x = a e si considerano le quantita' x e a/x. Se x < sqrt(a) allora a/x > a/sqrt(a), che e' uguale a sqrt(a): x < sqrt(a) < a/x. Analogamente, se x > sqrt(a) allora a/x < a/sqrt(a) = sqrt(a): x < sqrt(a) < a/x. Si ottine lo stesso risultato: la radice e' compresa tra x e a/x. Si puo' avvicinare la soluzione prendendo come nuovo x il valore mediano tra x a a/x e ripetere il procedimento. Ci si ferma quando la differenza tra tentativi successivi e' un valore molto piccolo. 19.2.3. Calcolo di pi greco con l'ago di Buffon (Georges-Louis Lecrerc de Buffon, 1707-1788, naturalista francese) Si lascia cadere molte un ago lungo un pollice su foglio di carta a righe, spaziate di due pollici, contando un centro se l'ago interseca una qualunque riga. Il quoziente tra tentativi e centri e' prossimo a pi greco. Simulazione: Basta considerare una piccola parte del foglio, con le ordinate che partono da 0 e arrivano a 3. Le righe sono in corrispondenza di 0 e di 2. - 77 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook La posizione x e' irrilevante; per la posizione dell'ago si puo' partire da una estremita' ylow e dall'angolo formato con le ascisse (0-180). La posizione yhigh si calcola come ylow + sin(alfa). Si fa centro se yhigh e' almeno uguale a 2. Programma Buffon.java import java.util.Random public class Buffon { public static void main (String[] args) { Random generator = new Random(); int hits =0 final int NTRIES = 10000; for (int i = 1; i <= NTRIES; i++){ // simula il lancio dell'ago: ylow in (0-2), angle in (0-180) double ylow = 2 * generator.nextDouble(); double angle = 180 * generator.nextDouble(); // calcola il punto in alto dell'ago double yhigh = ylow + Math.sin(Math.toRadians(angle)); if (yhigh >= 2) hits++; } // stampa il valore trovato presunto di pi greco System.out.println("tentativi/successi = " + (NTRIES * 1.0) / hits); } } - 78 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 20. ARGOMENTI AVANZATI DI JAVA 20.1. Riflessione Permette di agire sulle classi e sul loro comportamento. 20.2. Riflessione e classi Proxy Le classi prosy sono delle classi che si mettono in mezzo tra la classe chiamante e la classe chiamata per aggiungere delle funzionalita' senza modificare la classe di partenza. Un esempio puo' essere di aggiungere funzionalita' di tracing, di serializzazione (per produrre la versione di programma che non salva su file e quella che salva su file), di sincronizzazione... E' possibile anche utilzzare piu' proxy in cascata sulla classe target (quella nascosta). Se si usa la riflessione occorrera' pero' usare delle classi Factory. 20.2.1. Uso di classi proxy per il trace Tracing: per ogni classe si vuole eseguire, se richiesto, il tracing di ogni chiamata di metodo (parametri di ingresso e valore di ritorno). Scopo e' quello di abilitare e disabilitare il tracing di qualunque classe del sistema senza dover aggiungere codice alle classi o senza dover tenere allineate le classi e delle loro sottocloassi che per ogni metodo eseguono il tracing dell'input e del valore di ritorno. Vedere il documento pdf: Ira R. Forman, Nate Forman - Java Reflection in Action - cap. 4: Using Java's dynamic proxy. (Free excerpt, ho versione stampata). - 79 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 21. FONDAMENTI DELLA PROGRAMMAZIONE AD OGGETTI 21.1. Oggetti e classi Scopo: definire i concetti di oggetto, classe, metodo senza entrare nella sintassi di Java. Esempi: • 1.: forme grafiche che possono essere disegnate interattivamente • 2.: iscrizione degli studenti ad una classe 21.1.1. Argomenti • Definizioni • Creazione di oggetti • Chiamata di metodi • Parametri • Tipi di dati • Istanze multiple • Stato • Cosa c'e' in un oggetto • Interazione tra gli oggetti • Codice sorgente • Valore di ritorno • Oggetti come parametri 21.2. Approfondimenti sulla definizione di classi Scopo: vedendo la definizione di una classe si investiga su come viene scritto il codice per determinare il comportamento degli oggetti: come definire gli attributi e implementare i metodi. Esempio: • macchina distributrice di biglietti 21.3. Interazione tra oggetti Scopo: si vede come gli oggetti possono collaborare invocando i metodi di altri oggetti per realizzare uno scopo comune. Esempi: • orologio digitale con due implementazioni di display a due cifre • similazione di un sistema di gestione di e-mail 21.4. Raggruppamenti (collezioni) di oggetti Scopo: introdurre le collezioni di oggetti e le istruzioni per la gestione dei cicli. I vettori come tipo particolare di collezioni di oggetti. Esempi: • blocco note elettronico • analizzatore di web-log - 80 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 21.5. Librerie e documentazione Scopo: introdurrre le classi standard di Java, vedendo anche come leggere e capire la documentazione delle librerie. Importanza della documentazione nello sviluppo di programmi. Esempi: • sistema di dialogo Eliza-like • simulazione grafica di una palla che rimbalza 21.6. Test e debug Scopo: definire un insieme di regole per produrre classi corrette, comprensibili e facilmente manutebili. Per fare questo si discutono gli stili di scrittura del codice e dei commenti, le strategie di testing e di debugging Esempi: • agenda degli appuntamenti • calcolatrice elettronica 21.7. Disegno di classi Scopo: spiegare come si puo' dividere un problema in classi per consentire l'implementazione di una soluzione. Si parla di disegno responsibility-driven, accoppiamento, coesione, refactoring. Esempi: • gioco interattivo di tipo adventure game (RPG, Role Player Game) 21.8. Ereditarieta' e polimorfismo Scopo: capire ereditarieta', sottotipi, chiamata di metodi polimorfici, overriding di metodi. Esempi: • database di CD 21.9. Tecniche avanzate di astrazione: interfacce e classi astratte Scopo: approfondire il concetto di ereditarieta' introducendo le classi astratte e le interfacce Esempi: • simulazione del sistema prede-predatori 21.10. Gestione degli errori Scopo: introdurre la gestione degli errori Esempio: • estensione dell'esempio sull'agenda elettronica 21.11. Disegno di applicazioni Scopo: strutturare uno scenario definito vagamente in classi e metodi. I problemi trattati vanno dalla identificazione delle classi, di come devono interagire tra di loro e di come devono essere distribuite le responsabilita'. Esempio: • sistema di prenotazione dei posti al cinema. 21.12. Esercizi sui cicli • 1.: Itinerario casuale: simulare il percorso di un ubriaco che svolta a caso in un reticolo di - 81 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook strade di 10 righe orizzontali e 10 verticali. Dopo 100 svolte calcolare la distanza dal centro. Ci si aspetterebbe che non possa andare da nessuna parte, invece ci sono buone probabilita' che la persona esca da qualunque regione circoscritta con un adeguato numero di tentativi. • 2.: Traiettoria di un proiettile (simulazione, piu' efficace delle formule perche' consente di tenere conto del vento e della diversa forza di gravita' alle diverse altezze) • 3.: Serie di Fibonacci (f1=1, f2=1, f(n) = f(n-1) + f(n-2) per n > 2 • 4.: Calcolo di e^x con la formula 1 + x + (x^2/2!) + (x^3/3!) +... Si termina quando la differenza tra due valori successivi e' inferiore a un milionesimo del valore stesso. • 5.: Calcolo di pi greco con le gocce sul foglio quadrato: si espone alla pioggia un foglio di carta quadrato con inscritto un cerchio di diametro pari al lato del foglio. Il valore di pi greco e' ricavabile considerando il numero delle gocce cadute nelle due figure (quadrato e cerchio) proporzionale alle aree... Suggerimento: considerare il cerchio centrato in 0,0 e il quadrato con angoli nei punti 1,1 e -1,-1. • 6.: Grafico di una funzione in Java: disegnare 100 punti individuati dalle coppie (x, f(x)) e (x+d, f(x+d)) con x compreso tra x1 e x2 e d = (x2-x1)/100: utilizzare la funzione: f(x) = x^3/100 +-x + 10 e x1= -10, x2 =10 • 7.: Rosa dei venti: disegnarla usando le coordinate polari r=cos(2*teta), con teta compreso tra 0 e 360; 100 iterazioni. I valori di x e y valgono x = r cos(teta) e y = r sen(teta). Provare a trovare un metodo per variare il numero dei petali. - 82 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 22. DOCUMENTAZIONE 22.1. Cay Horstmann, Big java a. b. c. d. e. f. g. h. i. j. k. l. m. Introduzione Introduzione alle classi e agli oggetti Tipi di dato fondamentali Applets e grafica Decisioni (if) Iterazioni Disegno delle classi Test e debug Interfacce e polimorfismo .. .. Graphical User Interface .. 22.2. Cay Horstmann, Concetti di informatica e fondamenti di java 2 ATTENZIONE: nel libro non sono compresi i thread... 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. Introduzione Tipi di dato fondamentali Classi Applets e grafica Decisioni (if) Iterazioni Ancora sui metodi Test e debug Ereditarieta' gestione degli eventi Array e vettori Graphical User Interface Flussi ed eccezioni Progettazione orientata agli oggetti Algoritmi Introduzione alle strutture dati - 83 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 23. API LF Si trovano sotto Projects\Luigi\LFCommon\java. Documentazione in formato javadoc. (lfapi.doc\index.html) 23.1. lfapi package Esiste bldjar.bat che crea la libreria. I progetti che la utilizzano devono includere nel loro classpath d:\user\Luigi\Projects\LFcommon\lib\lfapi.jar per utilizzare le classi nei .java deve esserci: import lfapi.*; 23.1.1. ConfigFile Gestisce i file di configurazione delle variabili di una applicazione Una linea di definizione di un parametro ha la forma: nome=valore # eventuale commento. Le linee vuote, inizianti con '#' o che non contengono '=' sono ignorate. 23.1.2. ConnectionManager Stabilisce la connessione con il database server. 23.1.3. cpfile Sembra non essere quella corretta (vedi txtfile) 23.1.4. EnvironmentMap Definisce una mappa univoca per l'applicazione in cui tutte le classi possono depositare coppie chiave-valore. Esempio di uso: EnvironmentMap config = EnvironmentMap.getMap(); config.put("CHIAVE 1","Valore1"); config.put("chiave2", new Integer(800)); config.put("Chiave3", "10"); String valore1 = (String)(EnvironmentMap.getMap().get("CHIAVE 1")); int val1 = config.get("Chiave2"); // da verificare int val3 = Integer.parseInt((String)config.get("Chiave3")); String confString= "Configuration parameters:\n"; Set keyValues = config.entrySet(); Iterator it = keyValues.iterator(); while(it.hasNext()) { Map.Entry entry=(Map.Entry)it.next(); confString+= " " + entry.getKey() + " = "+entry.getValue()+ "\n"; } Usa il pattern Singleton. 23.1.5. FileInputHashMap 23.1.6. FileUtility 23.1.7. Log Esistono anche delle funzioni predefinite in java, vedi Java Tech Tip. 23.1.8. StringUtility - 84 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 23.1.9. ThumbnailBuilder Crea il thumbnail di una immagine JPEG, consentendo di specificare dimensioni massime e qualita' della riduzione. Un programma di esempio e' miniatore (dalla versione 1.01 in avanti) 23.1.10. ThumbnailSetBuilder Crea i thumbnail di tutte le immagini in una directory e nelle sue sottodirectory. Usa ThumbnailBuilder. 23.1.11. txtfile Gestione file di testo 23.1.12. URLReader Contine funzioni di utilita' per la gestione di URL. In particolare: • getHashMap: Interpreta il contenuto dell'URL come se si trattasse di un file di configurazione delle variabili di una applicazione. • readline: Legge una linea dall'URL. 23.2. lfapi.GUI package 23.2.1. ErrorWindow Apre una finestra mostrando la stringa e l'eventuale eccezione. 23.2.2. GenericTablePanel Fornisce funzioni aggiuntive per creare pannelli a partire da tabelle. Occorre definre una classe che faccia da modello di tabella. Utilizzare l'esempio fornito ExampleTableModel. 23.2.3. FormLayout Layout per la gestione di form 23.2.4. StatusBar Crea un testo da inserire nei pannelli con testo modificabile. - 85 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook 24. ESEMPI DI CODICE 24.1. JTable con diverse funzionalita'. Utilizza TableModel. Si tratta di una serie di scatole una dentro l'altra; in due casi ci sono dei pattern decorator. Implementa il pattern MVC (model = Table model, view = JTablePopup e JTable inclusa). +-------------------------------------------------+ | JDatiPanel | | +-------------------+ | | | JScrollPane | | | +-------------------+ | | | | | usa | | | | | v | | +-------------------+ +---------------+ | | |SortFilterModel | |JTablePopup | | | | +--------------+ | | +----------+ | | | | |DatiTableModel| | | |JTable | | | | | | | | | | (model)| | | | | | | | | | | | | | | | | | | <--------------+ | | | | | | | | | | | | | | | +--------------+ | | +----------+ | | | +-------------------| +---------------+ | | | +-------------------------------------------------+ Consente: • Scroll su numero di record maggiore di quelli visualizzabili (pattern Decorator) • Cambio dell'ordine di visualizzazione delle colonne (trascinando il titolo) • Ordinamento in base ai dati di una colonna (click sul titolo, pattern Decorator) • Autoresize delle colonne (c'e' del codice cablato forse da sistemare) • Pop-up menu' sul singolo record con attivazione di eventi che modificano i dati del record e lo rivisualizzano aggiornato • Refresh della JTable dopo TIMEOUT secondi Esempio di riga da mostrare nella JTable (src/JTable/Dato.java) /** * Classe di esempio per i dati da visualizzare */ import javax.swing.*; import java.awt.*; public class Dato { String str; int num; boolean flag; public Dato (int n, String s, boolean f) { str = s; num = n; flag = f; } public String toString() { return num+" "+str+" "+flag; } public int getNum() { return num;} public String getStr() { return str;} public boolean getFlag() { return flag;} public void setFlag(boolean f) { flag = f;} public Object[] getValues(int size) { Object[] row = new Object[size]; try{ // WARNING - 86 - Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook if (size==3) { row[0] = new Integer(num); row[1] = str; row[2] = new Boolean(flag); } }catch (ArrayIndexOutOfBoundsException e) { System.out.println("Dato: Invalid size " + size); System.exit(1); } return row; } public JPanel toJPanel(){ JPanel jp = new JPanel(); JLabel title = new JLabel("Dato "+str); JLabel info = new JLabel("Numero "+ num +"\n" + "Stringa: " + str +"\n" + "Flag: " + flag +"\n" ); jp.setLayout(new BorderLayout()); jp.setPreferredSize(new Dimension(600,580)); jp.setMinimumSize(new Dimension(600,580)); jp.add(title, BorderLayout.NORTH); jp.add(info, BorderLayout.SOUTH); return jp; } } Il pannello che contiene la JTable (src/JTable/DatoTablePanel.java) /** * Create a viewer for a generic table * * @author L. Ferrari - [email protected] * @version 1.0 21.9.2004 * @history 1.0 Versione originale */ import import import import import import import import import import import import java.awt.*; java.awt.event.*; java.applet.*; javax.swing.*; java.sql.*; java.util.*; javax.swing.table.*; java.io.StringWriter; java.io.PrintWriter; java.sql.*; java.net.*; java.io.File; public class DatoTablePanel extends JPanel { private static int PANELMINX=500; private static int PANELMINY=100; JScrollPane scrollPane = new JScrollPane(); JTablePopup jTable; JPopupMenu jPopupMenu; public DatoTablePanel(JPopupMenu pum) { super(); this.jPopupMenu=pum; scrollPane.setBorder(null); scrollPane.setMaximumSize(new Dimension(PANELMINX, PANELMINY)); scrollPane.setMinimumSize(new Dimension(PANELMINX, PANELMINY)); scrollPane.setOpaque(false); scrollPane.setPreferredSize(new Dimension(PANELMINX, PANELMINY)); this.add(scrollPane, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); } - 87 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook /* ----------------------------------------------------------------------------------* Fill input table and put it into table * non va bene se richiamata perche' fa perdere allineamenti. */ public void createViewerTable(ArrayList data, ArrayList titles) { // Create table jTable = new JTablePopup(jPopupMenu); try { DatiTableModel tm = new DatiTableModel(data, titles); SortFilterModel sfm = new SortFilterModel(tm); // Displaying Table jTable.setModel(sfm); jTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); jTable.setIntercellSpacing(new Dimension(5,0)); jTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); // AUTO RESIZE SECTION for (int col=0; col < jTable.getColumnCount(); col ++) { // Max caratteri: int maxLength = jTable.getColumnName(col).length(); //init con lun. nome for (int i=0; i < jTable.getRowCount(); i++) if (maxLength < String.valueOf(jTable.getValueAt(i,col)).length()) maxLength = String.valueOf(jTable.getValueAt(i,col)).length(); TableColumn cm = jTable.getColumn(jTable.getColumnName(col)); maxLength += 7; cm.setMaxWidth(maxLength*6); if (col == jTable.getColumnCount()-1) cm.setMaxWidth(630); //cm.setMinWidth(maxLength*6); cm.setMinWidth(6); //Per un resize da user cm.setPreferredWidth(maxLength*6); cm.setWidth(maxLength*6); /* DA FARE if(rs.getMetaData().getColumnTypeName(col+1).equals("NUMBER")) { DefaultTableCellRenderer dtcr = new DefaultTableCellRenderer(); dtcr.setHorizontalAlignment(JTextField.RIGHT); cm.setCellRenderer(dtcr); } */ } scrollPane.getViewport().add(jTable, null); // Resize ultima colonna: if (jTable.getSize().getWidth() < 600.0) jTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); //this.validate(); // END AUTO RESIZE SECTION sfm.addMouseListener(jTable); jTable.setDragEnabled(true); } catch (Exception e) { new ErrorWindow("ProcessTablePanel: CreateViewerTable",e); return; } this.validate(); } /* --------------------------------------------------------------------------------* Modello della jTable */ class DatiTableModel extends javax.swing.table.AbstractTableModel { private ResultSet rs; private java.util.AbstractList cache; private ArrayList titles; public DatiTableModel(ArrayList data, ArrayList titles) { this.titles=titles; cache = new java.util.ArrayList(); int cols = titles.size(); Iterator it = data.iterator(); while (it.hasNext()) { Object[] row = new Object[cols]; Dato p = (Dato)it.next(); row = p.getValues(cols); cache.add(row); } } Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 88 - LF Java Handbook public String getColumnName(int col) { try { return (String)titles.get(col); } catch (Exception e) { System.err.println("GetColumnName: "+e); return ""; } } public int getColumnCount() { try { return titles.size(); } catch (Exception e) { System.err.println("GetColumnCount: "+e); return 0; } } public Object getValueAt(int row, int col) { if (row < cache.size()) return ((Object[])cache.get(row))[col]; else return ""; } public int getRowCount() { return cache.size(); } } /* --------------------------------------------------------------------------------* Bridge class per implementare il sorting automatico cliccando sulle colonne */ class SortFilterModel extends AbstractTableModel { private class Row implements Comparable { public int index; public int compareTo(Object other) { Row otherRow = (Row)other; Object a; try { a = model.getValueAt(index,sortColumn); } catch (ArrayIndexOutOfBoundsException i) {a = "";} if (a == null) a = ""; Object b; try { b = model.getValueAt(otherRow.index, sortColumn); } catch (ArrayIndexOutOfBoundsException i) {b = "";} if (b == null) b = ""; if (a instanceof Comparable) return ((Comparable)a).compareTo(b); else return index - otherRow.index; } } private Row[] rows; private TableModel model; private int sortColumn; public SortFilterModel (TableModel m) { model = m; rows = new Row[model.getRowCount()]; for (int i = 0; i < rows.length; i++) { rows[i] = new Row(); rows[i].index = i; } } public void sort (int c) { sortColumn = c; Arrays.sort(rows); fireTableDataChanged(); } public void addMouseListener(final JTable table) { table.getTableHeader().addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent event) { //if (event.getClickCount() < 2) return; int tableColumn = table.columnAtPoint(event.getPoint()); int modelColumn = table.convertColumnIndexToModel(tableColumn); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 89 - LF Java Handbook sort(modelColumn); } }); } public Object getValueAt(int r, int c) { return model.getValueAt(rows[r].index,c); } public boolean isCellEditable(int r, int c) { return model.isCellEditable(rows[r].index,c); } public int getRowCount() { return model.getRowCount(); } public int getColumnCount() { return model.getColumnCount(); } public String getColumnName(int c) { return model.getColumnName(c); } public Class getColumnClass(int c) { return model.getColumnClass(c); } } /* ----------------------------------------------------------------------------------------* Classe che realizza la gestione del mouse per le funzioni pop-up * */ class JTablePopup extends JTable { JPopupMenu jPopupMenu; public JTablePopup(JPopupMenu pum) { super(); this.jPopupMenu=pum; this.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) popupShow(e); } public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) popupShow(e); } public void mouseClicked(MouseEvent e) { if (e.isPopupTrigger()) popupShow(e); } }); } private void popupShow (MouseEvent e) { //System.out.println("JablePopup - popupShow Row: "+this.getSelectedRow()); if (this.getSelectedRow()!= -1) { jPopupMenu.show(this, e.getX(), e.getY()); } } } /** --------------------------------------------------------------------------------------* Classe per la gestione degli errori */ private class ErrorWindow extends JOptionPane { public ErrorWindow (String s, Exception e ) { String text = s + "\n\n"; if (e!= null) { text+= e + "\n"; StringWriter out = new StringWriter(); e.printStackTrace(new PrintWriter(out)); text += out.toString(); } showMessageDialog(null, text, "JTable Test Error Window", JOptionPane.WARNING_MESSAGE); } public ErrorWindow ( Exception e ) { this("Exception",e); } public ErrorWindow ( String s) { this(s,null); } } - 90 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook } Classe di lancio con GUI (src/JTable/DatoTablePanelTest.java) import import import import import import import import import import java.awt.*; java.awt.event.*; java.awt.event.KeyEvent; javax.swing.KeyStroke; java.applet.*; javax.swing.*; java.sql.*; java.net.*; java.io.File; java.util.*; public class DatoTablePanelTest extends JApplet { DatiList listaDati; // list of data String user; boolean debug = true; String AppletURL = null; String imagesPath = ""; String img; // MenuBar and Menu JMenuBar jMasterMenu = new JMenuBar(); JMenu jMenuFile; JMenu jMenuDato; JMenu jMenuHelp; JPopupMenu jPopupMenu; static boolean isStandalone = false; static String windowTitle = "JTable tester - Copyright (C) Luigi Ferrari"; boolean popupMenuEnabled = true; private private private private private JPanel mainPanel = new JPanel(); JPanel messagePanel = new JPanel(); DatoTablePanel datiPanel; JTextField statusBar = new JTextField(); LinkedHashMap config = new LinkedHashMap(); // Applet parameters int requestedWidth = 0; int requestedHeight = 0; /* ----------------------------------------------------------* getParameter */ public String getParameter(String key, String def) { return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def); } /* ----------------------------------------------------------* PopupMenuEnable */ public boolean getPopupMenuEnabled () { return this.popupMenuEnabled; } public void setPopupMenuEnabled (boolean b) { popupMenuEnabled = b; } /* ----------------------------------------------------------* Init / start /stop */ public void init() { //default config values config.put("WIDTH",new Integer(800)); config.put("HEIGH",new Integer(600)); config.put("TIMEOUT","60"); // timeout in secondi config.put("VERSION","1.0.0"); config.put("DEBUG", "true"); // reading parameters if running as applet. if (!isStandalone) { String windowWidthString = getParameter("WINDOWWIDTH"); if (windowWidthString != null) { - 91 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook try { requestedWidth = Integer.parseInt(windowWidthString); config.put("WIDTH",new Integer(requestedWidth)); } catch (NumberFormatException e) { //Use default width. } } String windowHeightString = getParameter("WINDOWHEIGHT"); if (windowHeightString != null) { try { requestedHeight = Integer.parseInt(windowHeightString); config.put("HEIGH",new Integer(requestedHeight)); } catch (NumberFormatException e) { //Use default height. } } String deb = getParameter("DEBUG"); if (deb != null) { deb=deb.toLowerCase(); if(deb.equals("true")||deb.equals("false")) config.put("DEBUG", deb); } } // set debug debug=(config.get("DEBUG").equals("true")?true:false); if ((requestedWidth > 0) | (requestedHeight > 0)) { this.resize(Math.max(requestedWidth,this.getSize().width), Math.max(requestedHeight, this.getSize().height)); } // read process table listaDati = new DatiList(); jMenuFile=createMenuFile(); jMenuDato=createMenuDato(); jMenuHelp=createMenuHelp(); jPopupMenu=createPopupMenuDato(); jMasterMenu.add(jMenuFile); jMasterMenu.add(jMenuDato); jMasterMenu.add(Box.createHorizontalGlue()); jMasterMenu.add(jMenuHelp); datiPanel = new DatoTablePanel(jPopupMenu); datiPanel.setMinimumSize( new Dimension(200, 300)); datiPanel.createViewerTable(listaDati.getData(), listaDati.getTitles()); statusBar.setText("Welcome to JTable tester."); statusBar.setEditable(false); statusBar.setHorizontalAlignment(SwingConstants.LEFT); statusBar.setBackground(Color.WHITE); messagePanel.setMinimumSize( new Dimension(300, 20)); messagePanel.setPreferredSize( new Dimension(300, 20)); messagePanel.setBackground(Color.RED); messagePanel.setLayout(new BorderLayout()); messagePanel.add(statusBar,BorderLayout.SOUTH); mainPanel.add(datiPanel,BorderLayout.CENTER); mainPanel.setBackground(Color.YELLOW); mainPanel.add(messagePanel,BorderLayout.SOUTH); this.getContentPane().add(mainPanel, BorderLayout.CENTER); this.setJMenuBar(jMasterMenu); // il codice seguente e' replicato in repaint // perche' le JTable sono ricreate nuove... /* datiPanel.jTable.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { if (datiPanel.jTable.getSelectedRow()!=-1) { enableDatoMenu(); } } public void mouseReleased(MouseEvent e) { Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 92 - LF Java Handbook if (datiPanel.jTable.getSelectedRow()!=-1) { enableDatoMenu(); } } }); */ // fine codice replicato this.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(MouseEvent e) { enableDatoMenu(); } public void mousePressed(MouseEvent e) { enableDatoMenu(); } public void mouseClicked(MouseEvent e) { enableDatoMenu(); } }); } public void start() { statusBar.setText("Start.."); repaint(); jMenuFile.setEnabled(true); jMenuDato.setEnabled(false); jMenuHelp.setEnabled(true); class RefreshTimerListener implements ActionListener { public void actionPerformed(ActionEvent e) { refresh(); } } ActionListener listener = new RefreshTimerListener(); int millis = Integer.parseInt((String)config.get("TIMEOUT")) * 1000; System.out.println("Timeout in millisecondi di "+ millis); javax.swing.Timer t = new javax.swing.Timer(millis, listener); /* abilitare se si vuole una rilettura dei dati ogni * TIMEOUT secondi */ //t.start(); } public void stop() { statusBar.setText("Stop.."); repaint(); } /** Aggiorna il pannello in base ai dati correnti */ public void repaint(){ GregorianCalendar gc = new GregorianCalendar(); System.out.println("" + gc.get(Calendar.HOUR_OF_DAY)+":"+ gc.get(Calendar.MINUTE)+":"+gc.get(Calendar.SECOND)+"."+ gc.get(Calendar.MILLISECOND)+" Repaint."); Dato d = getSelectedDato(); datiPanel.createViewerTable(listaDati.getData(), listaDati.getTitles()); if (d!=null) setSelectedDato(d.getStr()); datiPanel.jTable.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { if (datiPanel.jTable.getSelectedRow()!=-1) { enableDatoMenu(); } } public void mouseReleased(MouseEvent e) { if (datiPanel.jTable.getSelectedRow()!=-1) { enableDatoMenu(); } } }); super.repaint(); } /* ------------------------------------------------------------------------* Menu' utilities */ private void setMenuItem(JMenuItem i, String text, int key, String icon){ i.setText(text); i.setMnemonic(key); //if (icon.length()>0) i.setIcon(createIcon(icon)); } private void setMenuItem(JMenuItem i, String text, int key){ i.setText(text); i.setMnemonic(key); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 93 - LF Java Handbook } /* -------------------------------------------------------------------------* MENU CONSTRUCTORS */ public JMenu createMenuFile(){ JMenu menu = new JMenu(); menu.setText("File"); menu.setMnemonic(KeyEvent.VK_F); menu.add(createPrintMenuItem()); menu.add(createQuitMenuItem()); return menu; } public JMenu createMenuDato(){ JMenu menu = new JMenu(); menu.setText("Dato"); menu.setMnemonic(KeyEvent.VK_D); menu.add(createEnableDatoItem()); menu.add(createDisableDatoItem()); menu.addSeparator(); // DEBUG menu.add(createProcessInfoItem()); return menu; } public JPopupMenu createPopupMenuDato(){ JPopupMenu menu = new JPopupMenu(); menu.add(createEnableDatoItem()); menu.add(createDisableDatoItem()); menu.addSeparator(); // DEBUG menu.add(createProcessInfoItem()); return menu; } public JMenu createMenuHelp(){ JMenu menu = new JMenu(); menu.setText("Help"); menu.setMnemonic(KeyEvent.VK_H); menu.add(createAboutMenuItem()); return menu; } /* Se una delle righe e' selezionata occorre poter lavorare * anche da menu' */ protected void enableDatoMenu() { if ((datiPanel.jTable.getSelectedRow()!=-1)) jMenuDato.setEnabled(true); else jMenuDato.setEnabled(false); repaint(); } /* -------------------------------------------------------------------------* MENU ITEMS CONSTRUCTORS */ public JMenuItem createPrintMenuItem(){ JMenuItem it = new JMenuItem(); setMenuItem(it, "Print", KeyEvent.VK_P, "Print16"); class PrintMenuItemListener implements ActionListener { public void actionPerformed(ActionEvent e) { print(); } } ActionListener listener = new PrintMenuItemListener(); it.addActionListener(listener); return it; } public JMenuItem createQuitMenuItem(){ JMenuItem it = new JMenuItem(); setMenuItem(it, "Quit", KeyEvent.VK_Q, "Stop16"); class QuitMenuItemListener implements ActionListener { public void actionPerformed(ActionEvent e) { quit(); } } ActionListener listener = new QuitMenuItemListener(); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 94 - LF Java Handbook it.addActionListener(listener); return it; } public JMenuItem createEnableDatoItem(){ JMenuItem it = new JMenuItem(); setMenuItem(it, "Enable", KeyEvent.VK_E); class EnableDatoMenuItemListener implements ActionListener { public void actionPerformed(ActionEvent e) { setEnable(true); } } ActionListener listener = new EnableDatoMenuItemListener(); it.addActionListener(listener); return it; } public JMenuItem createDisableDatoItem(){ JMenuItem it = new JMenuItem(); setMenuItem(it, "Disable", KeyEvent.VK_D); class DisableDatoMenuItemListener implements ActionListener { public void actionPerformed(ActionEvent e) { setEnable(false); } } ActionListener listener = new DisableDatoMenuItemListener(); it.addActionListener(listener); return it; } // DEBUG public JMenuItem createProcessInfoItem(){ JMenuItem it = new JMenuItem(); setMenuItem(it, "Info", KeyEvent.VK_I); class DatoInfoItemListener implements ActionListener { public void actionPerformed(ActionEvent e) { datoInfo(); } } ActionListener listener = new DatoInfoItemListener(); it.addActionListener(listener); return it; } // - DEBUG public JMenuItem createAboutMenuItem(){ JMenuItem it = new JMenuItem(); setMenuItem(it, "About", KeyEvent.VK_A, "Information16"); class AboutMenuItemListener implements ActionListener { public void actionPerformed(ActionEvent e) { about(); } } ActionListener listener = new AboutMenuItemListener(); it.addActionListener(listener); return it; } /* ------------------------------------------------------------------------* MENU EVENTS PROCESS */ protected Dato getSelectedDato() { String name =""; if (datiPanel.jTable.getSelectedRow()!=-1) name = (String)datiPanel.jTable.getModel().getValueAt( datiPanel.jTable.getSelectedRow(),1); return listaDati.getDato(name); } protected void setSelectedDato(String name) { int nrow = datiPanel.jTable.getRowCount(); for (int i = 0;i<nrow; i++){ if (datiPanel.jTable.getValueAt(i,1).equals(name)){ datiPanel.jTable.setRowSelectionInterval(i,i); return; //esce } } Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 95 - LF Java Handbook return; } protected void refresh () { Dato d = getSelectedDato(); statusBar.setText("Refresh.. (dato selezionato: "+d.getStr()+")"); /* Se i dati sono acquisiti da server * puo' essere necessario un aggiornamento... */ //listaDati.reload(); repaint(); } private void print () { statusBar.setText("Print.."); repaint(); /* ancora da fare new JOptionPanePrint(); */ statusBar.setText("Print executed"); repaint(); } private void quit () { statusBar.setText("Quit.."); repaint(); System.out.println("Quit.."); System.exit(0); } private void setEnable (boolean value) { System.out.println("SetEnable: Dato "+ getSelectedDato().getStr() + ": "+value); if (value) { statusBar.setText("Dato "+ getSelectedDato().getStr() + ": enable");; } else { statusBar.setText("Dato "+ getSelectedDato().getStr() + ": disable"); } getSelectedDato().setFlag(value); repaint(); } // DEBUG ------------------------------------------------------------------private void datoInfo () { statusBar.setText("View " +getSelectedDato().getStr() +" info.."); JPanel p=getSelectedDato().toJPanel(); JRootPane oldRP = this.getRootPane(); JRootPane newRP = new JRootPane(); this.setRootPane(newRP); JComponent c = (JComponent)this.getContentPane(); c.add (p); //this.setContentPane(c); repaint(); JOptionPane.showMessageDialog(null, "Info for "+getSelectedDato().toString()+" ."); this.setRootPane(oldRP); repaint(); } // - DEBUG ---------------------------------------------------------------private void about () { statusBar.setText("Display about dialog.."); repaint(); JOptionPane jop = new JOptionPane("TEST DELLA JTABLE (C)Luigi Ferrari"); jop.showMessageDialog(null,getAppletInfo()); statusBar.setText(""); repaint(); } /* ------------------------------------------------------------------------* get Applet Information */ public String getAppletInfo() { String host = "running standalone.."; if (!isStandalone) host =getCodeBase().getHost(); // read config String confString = ""; // if (((Boolean)config.get("DEBUG")).booleanValue()) { if (debug) { confString= "Configuration parameters:\n"; Set keyValues = config.entrySet(); Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] - 96 - LF Java Handbook Iterator it = keyValues.iterator(); while(it.hasNext()) { Map.Entry entry=(Map.Entry)it.next(); confString+= " " + entry.getKey() + " = "+entry.getValue()+ "\n"; } confString += "Applet URL: "+ (String)this.getParameter("AppletURL","")+"\n"; } return windowTitle + " \n\n" + " Running on: " + host + "\n" + " Java class version: " + System.getProperty("java.class.version") + "\n" + " Java version: " + System.getProperty("java.version") + "\n" + /* " HTTP Proxy Host: " + System.getProperty("http.proxyHost") + " port: " + System.getProperty("http.proxyPort") + "\n" + " HTTPS Proxy Host: " + System.getProperty("https.proxyHost") + " port: " + System.getProperty("https.proxyPort") + "\n" + */ " Client operating system architecture: " + System.getProperty("os.arch")+ "\n" + " Client operating system name: " + System.getProperty("os.name")+ "\n" + "\n" + confString + "\nCopyright (C) Luigi Ferrari <[email protected]>, Genova, Italia"; } /* ---------------------------------------------------------------------------* Gestione combinata applet e frame */ public static void main(String args[]) { isStandalone = true; JFrame mf = new JFrame(windowTitle); DatoTablePanelTest aef = new DatoTablePanelTest(); aef.init(); aef.start(); mf.getContentPane().add("Center", aef); mf.setSize(600,600); mf.show(); mf.setVisible(true); } /** * Crea una lista di oggetti di tipo Dato * * @author L. Ferrari - [email protected] * @version 1.0 21.9.2004 * @history 1.0 Versione originale */ public class DatiList { private ArrayList data; // leaf processes private ArrayList titles; // titles public DatiList() { titles = new ArrayList(); setTitles(titles); reload(); } private void setTitles(ArrayList t) { t.add("NUMERO"); t.add("STRINGA"); t.add("FLAG"); } public ArrayList getTitles() { return titles; } public ArrayList getData() { return data; } /* da rivedere la gestione delle eccezioni */ public void reload() { data = new ArrayList(); // dati per il test String[] datiDiTest = new String[10]; for(int i=0; i<10; i++) datiDiTest[i]=""+(100+i+1)+",dato"+(i+1)+","+(i%2==0); int j=0; - 97 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook try { //Legge da qualche parte i dati... String line=""; StringTokenizer tokenLine; String s=""; boolean f=false; int n=0; // data read while((line)!=null){ line=datiDiTest[j++]; // dati finti di prova if (debug) System.out.println("DEBUG: DatiList: read: "+line); if (line.trim().startsWith("<")) continue; if (line.length() == 0) continue; try { tokenLine = new StringTokenizer(line, ","); n=Integer.valueOf(tokenLine.nextToken()).intValue(); s=tokenLine.nextToken(); f=tokenLine.nextToken().equals("true"); }catch(NoSuchElementException e) { //invalid format line System.out.println("DatiList: Sintax error:\n" + "input line= "+line +"\n descarded."); continue; } Dato d = new Dato(n, s, f); data.add(d); // per ora... if(j==10) break; } }catch(Exception e) { System.out.println("DatiList: Found Exception "+e); }finally{ ; } } /** cerca un dato in base alla stringa */ public Dato getDato(String str){ Iterator it = data.iterator(); Dato d; while (it.hasNext()) { d = (Dato)it.next(); if (d.getStr().equals(str)) return d; } return null; } } } 24.2. Form layout Presi da Horstmann OO Design and Patterns. Layout per form per l'inserimento dati (src/FormLayout.java) import java.awt.*; /** A layout manager that lays out components along a central axis */ public class FormLayout implements LayoutManager { public Dimension preferredLayoutSize(Container parent) { Component[] components = parent.getComponents(); left = 0; right = 0; height = 0; for (int i = 0; i < components.length; i += 2) { Component cleft = components[i]; Component cright = components[i + 1]; Dimension dleft = cleft.getPreferredSize(); - 98 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook Dimension dright = cright.getPreferredSize(); left = Math.max(left, dleft.width); right = Math.max(right, dright.width); height = height + Math.max(dleft.height, dright.height); } return new Dimension(left + GAP + right, height); } public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } public void layoutContainer(Container parent) { preferredLayoutSize(parent); // Sets left, right Component[] components = parent.getComponents(); Insets insets = parent.getInsets(); int xcenter = insets.left + left; int y = insets.top; for (int i = 0; i < components.length; i += 2) { Component cleft = components[i]; Component cright = components[i + 1]; Dimension dleft = cleft.getPreferredSize(); Dimension dright = cright.getPreferredSize(); int height = Math.max(dleft.height, dright.height); cleft.setBounds(xcenter - dleft.width, y + (height - dleft.height) / 2, dleft.width, dleft.height); cright.setBounds(xcenter + GAP, y + (height - dright.height) / 2, dright.width, dright.height); y += height; } } public void addLayoutComponent(String name, Component comp) {} public void removeLayoutComponent(Component comp) {} private private private private int left; int right; int height; static final int GAP = 6; } Classe di test (src/FormLayoutTester.java) import java.awt.*; import javax.swing.*; public class FormLayoutTester { public static void main(String[] args) { JFrame frame = new JFrame(); frame.setLayout(new FormLayout()); frame.add(new JLabel("Name")); frame.add(new JTextField(15)); frame.add(new JLabel("Address")); frame.add(new JTextField(20)); frame.add(new JLabel("City")); frame.add(new JTextField(10)); frame.add(new JLabel("State")); frame.add(new JTextField(2)); frame.add(new JLabel("ZIP")); frame.add(new JTextField(5)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); } - 99 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected] LF Java Handbook } - 100 Rel. 1.0 del 11.12.2006 - Copyright Luigi Ferrari, [email protected]