mercoledì 27 febbraio 2008

Image Tooltip

Ho finalmente finito, più o meno, il primo applicativo "reale" con gwt.
Come anticipato ho creato un modulo gwt che per ogni immagine in una pagina web (con una determinata classe) crei un "tooltip" con l'immagine a grandezza "naturale" che compaia quando si passa con il mouse sopra l'immagine stessa.
In pratica il modulo parserizza tutta la pagina per cercare immagini con la data classe. Per ognuna di queste immagini crea un widget (una window di gwt-ext) con la stessa grandezza dell'immagine, contenente l'immagine stessa. A questo widgets viene aggiuntpo un ascoltatore per il mouse, e in caso di mouse hover si attiva (con una simpatica animazione fornita da gwt-ext), attiva una nuova window che carica la versione ad alta risoluzione dell'immagine (sul server ci devono essere quindi due immagini, l'immagine originale e una miniatura con lo stesso nome + "_th").
Funziona tutto ok... meno bene la gestione del ridimensionamento della finestra del browser... i widgets della miniatura si spostano correttamente, le dimensioni del tooltip vengono correttamente calcolate (perchè in base al viewport del browser riduco la grandezza dell'immagine originale), ma la posizione e la grandezza del gagtes "tooltip" contenitore fanno un po' quello che vogliono... ma solo in caso di ridimensionamento.

Ora comunque, visto che riesco a creare qualcosina, anche se semplice, con gwt e gwt-ext, sposto l'attenzione su XSTM



codice per IMGTOOLTIP, Versione.... diciamo 0.5



package mie.prove.client;

import java.util.ArrayList;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.MouseListenerAdapter;
import com.google.gwt.user.client.WindowResizeListener;
import com.gwtext.client.widgets.layout.FitLayout;
import com.gwtext.client.widgets.Component;

public class GwtImageTooltip implements EntryPoint {

ArrayList immagineTHWList = new ArrayList();
ArrayList imgList = new ArrayList();
ArrayList TTwindowList = new ArrayList();
ArrayList immagineToolTipList = new ArrayList();
ArrayList misureOriginaliImmaginiTT = new ArrayList();
int viewportW, viewportH;

public void onModuleLoad() {
viewportW = Window.getClientWidth();
viewportH = Window.getClientHeight();
com.google.gwt.core.client.GWT.log("il viewport ha altezza" + viewportH + " e larghezza " + viewportW,null);

Element elemento = DOM.getElementById("contenuto");
imgList = getElementsByClass(elemento, "img_tooltip");
int numImg = imgList.size();
for (int i=0; i < numImg; i++){
com.google.gwt.core.client.GWT.log("processo il tooltip numero"+i,null);

String urlImmagineTH = DOM.getElementProperty((Element)imgList.get(i), "src");
String altImmagineTH = DOM.getElementProperty((Element)imgList.get(i), "alt");

int imgY = DOM.getAbsoluteTop((Element)imgList.get(i));
int imgX = DOM.getAbsoluteLeft((Element)imgList.get(i));
int[] posizioneImmagine = {imgX,imgY};
com.google.gwt.core.client.GWT.log("l'immagine"+i+" si trova in posizione "+imgX+" "+imgY,null);

Image immagineTH = new Image(urlImmagineTH);

final com.gwtext.client.widgets.Window immagineTHWindow = new com.gwtext.client.widgets.Window();
/*
//per farlo diventare esattamente come un immagine
immagineTHWindow.setFrame(false);
immagineTHWindow.setHeader(false);
immagineTHWindow.setHeaderAsText(false);
//fine per farlo diventare esattamente come un immagine
*/
immagineTHWindow.setLayout(new FitLayout());
immagineTHWindow.add(immagineTH);
//immagineTHWindow.anchorTo((Element)imgList.get(i), position, offsetXY)
immagineTHWindow.setModal(false);
immagineTHWindow.setPixelSize(immagineTH.getWidth(),immagineTH.getHeight());
immagineTHWindow.setDraggable(false);
immagineTHWindow.setClosable(false);
immagineTHWindow.setResizable(false);
immagineTHWindow.setFooter(true);
immagineTHWindow.setTitle(altImmagineTH);
immagineTHWindow.setPosition(imgX,imgY);
immagineTHWindow.show();

//aggiungo la window immagineTHWindow alla lista immagineTHWList
immagineTHWList.add(immagineTHWindow);

String urlTT = urlImmagineTH.replaceAll("_th", "");
Image immagineToolTip = new Image(urlTT);
immagineToolTip.setVisible(false);
immagineToolTipList.add(immagineToolTip);
int[] misureOriginali = {immagineToolTip.getWidth(),immagineToolTip.getHeight()};
misureOriginaliImmaginiTT.add(misureOriginali);

int [] misureTTwindow = calcolaMisuraTTwindow(posizioneImmagine,immagineToolTip);
int immagineTTW = misureTTwindow[0];
int immagineTTH = misureTTwindow[1];

immagineToolTip.setPixelSize(immagineTTW, immagineTTH);

final com.gwtext.client.widgets.Window TTwindow = new com.gwtext.client.widgets.Window();
TTwindow.setLayout(new FitLayout());
TTwindow.add(immagineToolTip);
TTwindow.setTitle(altImmagineTH);
TTwindow.setModal(false);
TTwindow.setDraggable(false);
TTwindow.setClosable(false);
TTwindow.setResizable(false);
TTwindow.setFooter(true);
TTwindow.setAnimateTarget((Element)imgList.get(i));
TTwindow.setPixelSize(immagineTTW, immagineTTH);

posizionaTTwindow(TTwindow, posizioneImmagine);

//aggiungo la window TTwindow alla lista TTwindowList
TTwindowList.add(TTwindow);

//agiungo ascoltatore eventi all'immagine per aprire tooltip
immagineTH.addMouseListener(new MouseListenerAdapter() {
public void onMouseEnter(Widget sender) {
TTwindow.show();
Component immagineToolTip = TTwindow.getComponent(0);
immagineToolTip.setVisible(true);
}
});

//agiungo ascoltatore eventi mouse al tooltip per chiuderlo
immagineToolTip.addMouseListener(new MouseListenerAdapter() {
public void onMouseLeave(Widget sender) {
TTwindow.hide();
}
});
}

//aggiungo l'ascoltatore alla finestra per spostare le immagini in caso di resize
Window.addWindowResizeListener(new WindowResizeListener(){
public void onWindowResized(int x, int y){
aggiornaPosizioneimmaginiTHWindow(immagineTHWList);
viewportW = Window.getClientWidth();
viewportH = Window.getClientHeight();
aggiornaMisureTTwindow(TTwindowList,imgList,immagineToolTipList);
aggiornaPosizioniTTwindows(TTwindowList,imgList);
}
});
}

public void aggiornaMisureTTwindow(ArrayList TTwindowList, ArrayList imgList, ArrayList immagineToolTipList){
int numImg = TTwindowList.size();
int [] posizioneImmagine = new int[2];
for (int i=0; i < numImg; i++){
com.gwtext.client.widgets.Window TTwindow = (com.gwtext.client.widgets.Window)TTwindowList.get(i);
try{
int imgY = DOM.getAbsoluteTop((Element)imgList.get(i));
int imgX = DOM.getAbsoluteLeft((Element)imgList.get(i));
posizioneImmagine[0] = imgX;
posizioneImmagine[1] = imgY;
}
catch(IndexOutOfBoundsException e){
System.err.print("IndexOutOfBoundsException: ");
System.err.println(e.getMessage());
com.google.gwt.core.client.GWT.log("IndexOutOfBoundsException: ",null);
com.google.gwt.core.client.GWT.log(e.getMessage(),null);
}
Image immagineToolTip = (Image)immagineToolTipList.get(i);
int[] misureOriginali = (int[])misureOriginaliImmaginiTT.get(i);
immagineToolTip.setPixelSize(misureOriginali[0], misureOriginali[1]);
int [] misureTTwindow = calcolaMisuraTTwindow(posizioneImmagine,immagineToolTip);
int immagineTTW = misureTTwindow[0];
int immagineTTH = misureTTwindow[1];
com.google.gwt.core.client.GWT.log("misure ricalcolate: imgx="+immagineTTW+" imgy="+immagineTTH,null);
immagineToolTip.setPixelSize(immagineTTW, immagineTTH);
TTwindow.setPixelSize(immagineTTW, immagineTTH);
}
}

public int[] calcolaMisuraTTwindow(int[] posizioneImmagine, Image immagineToolTip){
float resize = 1; //% di resize in caso l'immagine sia troppo grande
int immagineTTH = immagineToolTip.getHeight();
int immagineTTW = immagineToolTip.getWidth();
String url = immagineToolTip.getUrl();

com.google.gwt.core.client.GWT.log("L'immagine tooltip ha altezza" + immagineTTH + " e larghezza " + immagineTTW + " e url = " +url,null);

//se l'immagine è più grande del viewport, devo scalarla e posizionarla centrata
if ((immagineTTW > viewportW-10) || (immagineTTH > viewportH-10)){
if (immagineTTW > viewportW-10){
resize = (float)immagineTTW / ((float)viewportW-10);
}
else {
resize = (float)immagineTTH/((float)viewportH-10);
}
float temp = (immagineTTW/resize);
immagineTTW = Math.round(temp);
temp = (immagineTTH/resize);
immagineTTH = Math.round(temp);
}
int [] misureTTwindow = {immagineTTW,immagineTTH};
return misureTTwindow;
}

public void aggiornaPosizioniTTwindows(ArrayList TTwindowList, ArrayList imgList){
int numImg = TTwindowList.size();
for (int i=0; i < numImg; i++){
com.gwtext.client.widgets.Window TTwindow = (com.gwtext.client.widgets.Window)TTwindowList.get(i);
int imgY = DOM.getAbsoluteTop((Element)imgList.get(i));
int imgX = DOM.getAbsoluteLeft((Element)imgList.get(i));
int [] posizioneImmagine = {imgX,imgY};
posizionaTTwindow(TTwindow,posizioneImmagine);
Component immagineToolTip = TTwindow.getComponent(0);
immagineToolTip.setVisible(false);
}
}

public void posizionaTTwindow(com.gwtext.client.widgets.Window TTwindow, int[] posizioneImmagine){
int posTTX = posizioneImmagine[0]; //posizione X del tooltip
int posTTY = posizioneImmagine[1]; //posizione Y del tooltip
int spostTTX = 0; //spostamento del tooltip nel caso l'immagine sia larga
int ttwindowWidth = TTwindow.getWidth(); //larghezza tooltip
//se l'immagine TT è troppo larga per stare nella posizione dell'immagine TH, la sposto a sinistra
if (posTTX + ttwindowWidth > viewportW-5){
spostTTX = posTTX + ttwindowWidth - (viewportW-5);
}
TTwindow.setPagePosition(posTTX-spostTTX,posTTY);
}

//imgList e immagineTHWList hanno gli stessi indici
public void aggiornaPosizioneimmaginiTHWindow(ArrayList immagineTHWList){
int numImg = immagineTHWList.size();
for (int i=0; i < numImg; i++){
int imgY = DOM.getAbsoluteTop((Element)imgList.get(i));
int imgX = DOM.getAbsoluteLeft((Element)imgList.get(i));
com.gwtext.client.widgets.Window currentWindow = (com.gwtext.client.widgets.Window)immagineTHWList.get(i);
currentWindow.setPosition(imgX,imgY);
}
}

private ArrayList getElementsByClass(Element parent, String className){
ArrayList list = new ArrayList();
Element current = DOM.getFirstChild(parent);
String classe = null;

while(current != null){
classe = DOM.getElementProperty(current, "className");
if (classe!=null){
if(classe.equals(className)){
com.google.gwt.core.client.GWT.log("trovato un img_tooltip",null);
list.add(current);
}
}
current = DOM.getNextSibling(current);
}
return list;
}
}


mercoledì 20 febbraio 2008

Gwt-Ext

Gwt-Ext (http://gwt-ext.com/) sembrerebbe una libreria ben fornita. Anche Francesco ne è rimasto positivamente colpito. Sto provando a creare una mini applicazione con gwt-ext, un tooltip per le immagini...
Vorrei che in una pagina web ci siano delle miniatura delle immagini, e passando il mouse sopra l'immagine si apra un tooltip contenente l'immagine in grandezza originale.
Userei i tooltip presenti in gwt-ext, che accettano anche del codice html.

Dal wiki di GWT-EXT: Introduction to GWT Ext 2.0
Bisogna anche scaricare la libreria Ext-Js (http://extjs.com/download)

  1. una volta creato il progetto in eclipse, copiare queste cartelle di ext-js
    * /adapter
    * /resources
    * ext-all.js
    * ext-all-debug.js
    * ext-core.js
    * ext-core-debug.js
    nella cartella src/com/mycompany/mypackage/public/js (ovviamente adattata ai nomi del package)

  2. importare la libreria nel progetto: Tasto destro del mouse sul progetto, in eclipse, "build path"->"configure build path"->"libraries"->"add external jar" e si individua il jar di gwt-ext

  3. Successivamente bisogna inserire nel file di configurazione xml "nomeprogetto.gwt.xml" queste due righe, prima dell'importazione della classe del progetto

    <!-- Inherit the GWTExt Toolkit library configuration.      -->

    <inherits name="'com.gwtext.GwtExt'">

    </inherits>

  4. nel file html inserire queste righe

    <!-- Begin ExtJS library files -->
    <link rel="stylesheet" type="text/css" href="js/ext/resources/css/ext-all.css"/>
    <script type="text/javascript" src="js/ext/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="js/ext/ext-all.js"></script>
    <!-- End ExtJS library files -->


    prima dell'inclusione del js del progetto

Per ora ho creato la funzione che scorre la pagina e trova tutte le immagini con la classe css "img_tooltip". Per ogni immagine crea una lista che da in pasto poi alla funzione che attaccherà ad ogni immagine il tooltip stesso.

Vediamo cosa riesco a fare.

venerdì 15 febbraio 2008

Risorse GWT

Ora mi sono messo in rete a spulciare un po' di risorse per GWT, così nei prossimi giorni mi studio altro e provo a sviluppare qualcosa in GWT. Il fine primario è quello sia di imparare meglio a programmare in Java, sia famigliarizzare di più con GWT ma soprattutto tenere a mente l'obbiettivo che devo pormi per la il progetto/tesi: trovare un modo per sviluppare uno strato intermedio tra il server e il client... andando a fare qalcosa di simile a ciò che fa già echo2; in pratica fare in modo di non dover usare solo RPC per ogni interazione del client, ma cercare di pensare sul server la stessa logica sul client, fare comunicare le due logiche e interagire solo con quella lato server

  • GWT Windows Manager (http://www.gwtwindowmanager.org/)
    Offre un sistema "ad alto livello" per la creazione/gestione di finestre e finestre di dialogo. Davvero bello e ben fatto. Da tenere in considerazione.
  • GWT-EXT (http://gwt-ext.com/)
    Libreria fornitissima, con alberi, finestre, layout, e veramenti molti widgets, alcuni interessantissimi.
  • GWTSITE (http://www.gwtsite.com/)
    Un blog con un sacco di risorse interessanti, link utili, tutorial ecc..
  • OnGWT (http://www.ongwt.com/)
    Altro blog aggiornato con risorse su GWT
  • Tutorial GWT
    Un elenco di 17 nuovi tutorial su GWT, alcuni sembran interessanti, altri meno
  • XSTM (http://www.xstm.net/)
    Replicazione e sincronizzazione di oggetti, tra client e client, o client e server, per Java, .NET e GWT. Può esserci molto utile
  • GWT-Tooling (http://code.google.com/p/gwt-tooling/)
    Plugin per Eclipse... questo pare funzionare davvero. Dopo averlo installato, per usarlo, in Eclipse creo un nuovo progetto Web dinamico, seleziono Apache Tomcat 6 come Target Runtime, e seleziono "dinamic web project using GWT" in configuration. Poi una volta creato il progetto, lo seleziono, e con il destro "new" "other" "GWT" "Gwt module". Poi "run on server" (in realtà forse bisogna selezionare run as -> open run dialog -> GWTBrowser)
  • MyGWT (http://mygwt.net)
    Libreria con alcuni riguardi vero il pattern Model-View-Controller (MVC)
  • GWT Small Guide: Integrazione GWT e PHP con JSON

I 3 metodi di compilazione di GWT

Stamattina ho praticamente terminato la "lettura" del libro "GWT in Action".
Ho provato a spulciare qualche file js generato dalal compilazione del progetto del libro, Dashboard... illeggibile. Questo è normale, perchè il compilatore di GWT, in maniera standard, genera del codice supercompresso, illeggibile in pratica dall'uomo.
Esistono tre stili di compilazione, dal più compresso al più verboso. Ho provato a controllare la grandezza dei file generati, e la differenza è impressionante.

La scelta del tipo di compilazione la si fa con il parametro -style dato in pasto al compilatore. Questo lo si fa normalmente modificando il file nomeprogetto-shell.cmd, con questi parametri OBFUSCATED, PRETTY e DETAILED.

Ho compilato il progetto contenuto nel libro, GWT in Action, scaricabile anche dal forum/sito del libro (http://www.manning.com/hanson/), e questo è il risultato.

  • -style OBFUSCATED (dovrebbe valere anche OBF): occupazione cartella www = 10,4 MB
    codice illeggibile, adatto per la compilazione finale, per la messa online del lavoro
  • -style PRETTY : occupazione cartella www = 24,8 MB
    codice leggibile, ma con alcuni nomi compressi e codice non troppo lineare
  • -style DETAILED: occupazione cartella www = 61,2 MB
    codice leggibile, esteso, più lineare e descrittivo
La differenza di occupazione di memoria è impressionante, (compressione all'83%... il file generati da obfuscated pesano il 17% rispetto ai file generati da detailed). Ed essembito in ambito web, o comunque di passaggio file attraverso una rete, questa differenza è enorme in termini prestazionali.

giovedì 7 febbraio 2008

Convenzioni sui nomi in Java

Dal sito di Java (http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html) presento qui le convenzioni per la rappresentazioni dei nomi in un progetto Java.

  • Package: impotante utilizzare le convenzioni per evitare conflitti sui nomi, soprattutto nel caso di utilizzo di package importati da terze fonti.
    • I nomi dei package vanno scritti tutti in minuscolo.
    • Se si appartiene/lavora per una compagnia che ha un dominio internet, lo si usa all'inizio del nome del package, prima il "suffisso" del nome a dominio (il dominio di primo livello) poi il dominio effettivo della compagnia (il dominio di secondo livello). Nel casa dei package della Sun si ha "com.sun".
    • Se il nome a dominio contiene caratteri speciali non usabili nel nome del package, bisogna convertirli in underscore (per esempio se il nome a dominio è una keyword o se il nome inizia con un numero.
    • Se si vuole indicare un sottodominio, lo si può fare, sempre con la logica di scrivere il nome a dominio in maniera inversa, cioè primolivello.secondolivello.sottodominio
    • Si può specificare anche il nome dle progetto o della persona che ha sviluppato il package, sempre con la logica di inserirlo in fondo al nome del package.
    • Esempi validi sono, per esempio
      com.java
      com.apple.quicktime.v2
  • Classi e interfacce: Anche in questo caso è buona norma rispettare le seguenti convenzioni
    • i nomi dovrebbero rappresentare sostantivi o frasi descrittive non eccessivamente lunghe
    • La prima lettera deve essere maiuscola, le altre minuscolo.
    • Se il nome è composto da più parole, vanno scritte attaccate, con la prima lettera di ognuna in maiuscolo
    • Il nome dovrebbe essere descrittivo della classe, avere un senso, una connessione al significato semantico della classe stessa
    • Sono da evitare i verbi, riservati ai metodi
    • Esempi di nomi corretti per classi ed interfacce sono:
      ClassLoader
      SecurityManager
      Thread
      Dictionary
  • Metodi: utile anche in questo caso rispettare le convenzioni
    • il nome di un metodo dovrebbe essere costituito da un vervo che spieghi l'azione del metodo stesso, scritto in minuscolo.
    • Se si vuole usare più di una parola, contenenti comunque in verbo, la prima parola deve essere minuscola e le altre avere la prima lettera maiuscola.
    • Metodi che leggono e settano una variabile, dovrebbero indicare come prima parola, rispettivamente, get e set, seguita dal nome di variabile interessata
    • Metodi che servono per ricavare la lunghezza di un oggetto dovrebbero chiamarsi lenght
    • Metodi che verificano una variabile booleana dovrebbero chiamarsi is seguita dal nome di variabile da verificare
    • Nomi corretti di metodi sono
      getV
      setV
      isV
      toV
      sommaCostanti
  • Fields (non so bene cosa siano)
    • Names of fields that are not final should be in mixed case with a lowercase first letter and the first letters of subsequent words capitalized.
    • Note that well-designed classes have very few public or protected fields, except for fields that are constants (final static fields).
    • Fields should have names that are nouns, noun phrases, or abbreviations for nouns.
  • Costanti:
    • Le costanti dovrebbero essere rappresentate da parole o frasi descrittive e/o abbreviazioni, scritte in maiuscolo, divise, se più parola, da un underscore.
    • Corretti nomi di costanti sono:
      MIN_VALUE
      MAX_VALUE
      PS_RUNNING
      S_SUSPENDED
  • Varibili locali e Parametri
    • Dovrebbero essere costituite da parole corte, o assemblamenti di lettere, sempre in minuscole, che non necessariamente formano una parola di senso compiuto
    • per esempio una variabile che contiene un riferimento all'oggetto ColoredPoint potrebbe chiamarsi cp
    • oppure buf potrebbe essere un buon nome per un puntatore ad un buffer
    • si dovrebbero evitare variabili di uan sola lettera, escludendo i cicli dove si possono usare (come la classica i) oppure se indicano un type, per esempio per convenzione si usa
      • b for a byte
      • c for a char
      • d for a double
      • e for an Exception
      • f for a float
      • i, j, and k for integers
      • l for a long
      • o for an Object
      • s for a String
      • v for an arbitrary value of some type

mercoledì 6 febbraio 2008

Cypal Studio for GWT

Leggengo "GWT in Action" scopro, e questo è un altro punto a favore di GWT, che esistono alcuni tool per aiutare la vita dello sviluppatore GWT (sì, ok, non posso ancora definirmi uno sviluppatore GWT, manco mi posso definire sviluppatore, però è interessante).
Tra questi un plug in di Eclipse che potrebbe tornarmi utile: Cypal Studio for GWT
E annesso a questo trovo anche un tutorial che mi insegna ad usare questo plugin: http://grprakash.googlepages.com/gwttutorialwithgooglipse

Ritorno a GWT

Parlando stamane con il mio correlatore, abbiamo pensato, soprattutto vista la non entusiastamente esperienza con la scarsa presenza di documentazione su Echo2/Cooee e la scarsa attività delle community a queste connesse, di riprovare a dare uno sguardo a GWT.

Questo perchè? Forse principalmente per la prima lettera di GWT... la G di Google. Dopotutto questa G da garanzie di stabilità futura, di continua manutenzione. Ma soprattutto è sinonimo di ottima documentazione, grande community e numerosi utilizzatori.

Per fare un esempio, se si cercano in rete tutorial o libri su GWT in breve tempo se ne trovano una marea... su Echo2/Cooee? Poco o nulla

L'idea è tornare su GWT per quanto riguarda l'aspetto client, il disegno dell'interfaccia web, e di pensare noi a qualcosa che possa interfacciarsi con questa per dialogare con il server, senza usare le RPC previste da google

Nel libro "GWT in Action", nella parte in cui si parla di un confronto/integrazione con Ruby On Rail si sottolinea che è possibile intraprendere questa strada: (PAG 24 del pdf)
GWT is client-centric, and most of what GWT does is on the client-side of the picture. It allows you to develop and display widgets using Java and write Java handlers to trap user-triggered actions. GWT can communicate with the server, as needed, which could be driven by user interaction, or perhaps a timed event.
GWT then allows you to compile all of the Java code to JavaScript so that the program can be run in the browser. On the server, GWT only provides a mechanism for serializing and desterilizing Java objects so that they can be received from the browser and sent back, and does not get involved in other aspects of the server.
Instead of competition between GWT and Ruby on Rails, we find an opportunity for integration. This is in part driven by the fact that GWT provides several non-proprietary schemes for passing data between client and server. We are finding that many developers who are starting to use GWT are using non-Java technologies on the server, and are looking at GWT to provide only client-side functionality.
Credo che il discorso si possa allargare ad ogni tecnologia (o quasi) ci sia su lato server. Ora mi studio ancora un po' GWT, sperando di riuscire ad apprenderlo a fondo in modo da concretizzare l'idea di realizzare un "interfaccia lato client con GWT e lato server con Java"

martedì 5 febbraio 2008

Cooee e i threads

Ieri e stamane ho provato a convertire le mie prove fatte con echo2, in cooee.
Non è un operazione molto difficile, basta cambiare, come spiegato qui http://www.karora.org/wiki/display/COO/Migrating+from+Echo2 , le referenze ai package di cooee.
In realtà ho dovuto cambiare anche altre cosucce, che non so bene spiegarmi (come cambiare il tipo Boolean in boolean... non so come mai), ma alla fine tutto sembra funzionare.

O quasi.

Le finestre funzionano, le aperture di quelle modali anche, il passaggi di parametri non ha problemi. A Parte qualche discrepanza (in Echo 2 i selectfilds si autoselezionano, almeno graficamente, mentre in cooee no, forse è anche meglio, dato che nemmeno in echo2 si selezioanno davvero in maniera automatica), è tutto ok.

Ma i threads paiono non andare, o meglio, sembra che non riescano ad aggiornare l'interfaccia utente
Exception in thread "conta2" java.lang.IllegalStateException: Attempt to update state of application user interface outside of user interface thread.
non so bene cosa significhi, ho chiesto un aiuto alla community... che però non sembra così attva come mi aveva indicato Fissore: http://www.karora.org/forum/thread.jspa?threadID=138&tstart=0
Staremo a vedere.

lunedì 4 febbraio 2008

Federico Fissore e Cooee

La settimana scorsa, tra le poche cose fatte, ho scritto a Federico Fissore (www.fissore.org), personaggio che spesso è "saltato fuori" durante le mie ricerche in internet riguardo a echo2. A quanto pare è uno degli italiani che ha sviluppato con questo fremowork.
Gli ho scritto chiedendogli un suo parere sul futuro di Echo2... gli ho spiegato la mia situazione chiedendogli qualche consiglio.
Prontissimo e gentilissimo mi ha risposto...

Incollo qui la sua rispota... può sempre essere utile a qualcun altro:

[...]
Dunque, se posso riassumere la tua mail, tu vuoi sapere se Echo2/3 sono
una soluzione viabile e, se sì, dove trovare documentazione più completa

Il mio parere, e mi spiace davvero tanto dirlo, è negativo: no, non mi
fiderei troppo di Echo2, per una somma di ragioni diverse, che ti
snocciolo perchè tu possa usarle anche in altri contesti

Framework per costruire Rich Internet Applications ce ne sono tanti,
troppi: spiccare fra gli altri è difficile.
GWT ci riesce per due motivi

* si chiama GOOGLE web toolkit (ChiTiConosce web toolkit non avrebbe
avuto lo stesso successo)
* come dicevo nell'intervista, GWT si presta più facilmente allo
sviluppo di applicazioni per il grande pubblico, il che significa
visibilità e passaparola

Tutti gli altri rimangono nelle nicchie, e lì gioca davvero il loro
valore e la loro community.
Sul valore di Echo2 non ho dubbi: è tecnicamente un OTTIMO strumento. Le
API sono chiare e semplici. Si possono fare (e ho fatto) cose moolto
interessanti con poche righe di codice. Personalmente mi sono davvero
divertito
Ma Echo2 è un prodotto di nicchia, gestito ahimè da un idiota, che

* non ha abbastanza soldi per sviluppare certe componenti importanti
* ha una community piccola, quindi in grado di sopperire alle
mancanze economiche con eccessiva lentezza
* non è molto propenso a dare accesso in scrittura ai membri anche
capaci della comunità, causando un rallentamento anche
nell'applicazioni delle patch proposte dai membri della comunità

Un'alternativa è Cooee (http://karora.org/), fork di Echo2, che promette di fare
manutenzione evolutiva sui componenti esistenti (evitando di rompere la
retro compatibilità come ha fatto Echo3). Anche qui, per quel poco che
ne so, la community è piccola

Quindi?
Ho lavorato con Echo2 per un anno, sviluppandoci 2 progetti. Oggi a quel
mio cliente propongo di passare a Cooee per non dover rifare tutto ma
per evitare di applicare delle patch fatte in casa come invece fa oggi
(le patch che ho sviluppato io e che sono sempre state ignorate
dall'idiota di prima, nonostante il numero di download di chi se le
voleva applicare a mano)

Se però dovessi cominciare un lavoro nuovo, penserei ad altro
ZK (http://zkoss.org/) sembra essere un buon prodotto: è GPL, quindi non ci si può fare
applicazioni proprietarie da redistribuire, ma continua a ricevere elogi
e chi lo ha usato qui a Torino me ne ha parlato bene
wingS (http://wingsframework.org/) è un altro progetto che mi attira: ha delle API molto simili a
Swing ed è sviluppato da tedeschi (quindi si "gioca in casa")
openlaszlo (www.openlaszlo.org/): altro progetto moolto interessante per supporto e
qualità finale del prodotto. Con la versione 4 hanno finalmente aggiunto
un rendering DHTML invece del solo rendering Flash (che 2 anni fa me lo
aveva fatto scartare)
[...]

venerdì 1 febbraio 2008

Lo switch in Java

Un'altra delle cose scoperte la settimana scorsa, che all'inizio mi ha lasciato nel panico, perchè non capivo cosa stesse succedendo, è che Java a uno switch... che funziona solo su integer...
Non conosco i moivi di questa scelta implementativa... che mi pare bizzarra... in un linguaggio dove puoi fare quasi tutto, questa è una limitazione non da poco

E a volte è proprio utile, soprattutto ai fini delal leggibilità del codice, eseguire uno switch su delle stringhe

Ok, ok, la soluzione potrebbe essere una serie di If elseif... ma ve lo immaginate un codice con una decina di elseif?
Uno schifo.

Certo, si potrebbe pure fare una mappatura "caratteri-integer", ma che barba... e poi risulterebbe meno leggibile il codice

Girovagando in rete ho trovato una soluzione abbastanza buona.
In pratica, prima di eseguire lo switch, si crea una costante Enum, elencando come contenuti enumerativi le stringhe che si vogliono usae... e poi switchare su queste

Esempio, ho una variabile stringa che può assumere questi valori "carne, pesce, dolce, contorno, frutta" e voglio creare uno switch su questa variabile sringa
Si prosegue così:
  • Definire una costante enum con i valori congruenti alle stringhe che si vogliono prendere in considerazione

    enum portate {
    carne, pesce, dolce, contorno, frutta
    }


  • Successivamente eseguire uno switch con un valueof(costanteenum). Il valueof fa una comparazione tra le stringhe e i valori di enum. Si può usare toLowerCase per un confronto non case sensitive

    switch (portate.valueOf(e.getActionCommand().toLowerCase())){
    case carne:
    bla bla
    break;

    [...]

    case frutta:
    bla bla
    break;
    }

  • L'unico problema è che così si potrebbero sollevare delle eccezioni IllegalArgumentException or NullPointerException (penso che succeda se la stringa ha un valore che non ha corrispondenze nell'enum. Si possono gestire con un Try-catch

    enum portate {

    carne, pesce, dolce, contorno, frutta;

    public static portate cercaportata(String stringa)
    {
    try {
    return valueOf(strimga);
    }
    catch (Exception ex) {
    return NOVALUE;
    }
    }
    }

    switch (portate.valueOf(e.getActionCommand().toLowerCase())){
    case carne:
    bla bla
    break;

    [...]

    case frutta:
    bla bla
    break;

    default:
    bla bla per valori non presenti nell'enum
    }

Thread & company

Durante questa settimana non sono riuscito a fare molto.
Ieri ho dato il mio ultimo esame... laboratorio di sistemi operativi
Quindi un giorno di lavoro in meno, in più non sono stato nemmeno bene... insomma ho lavorato ben poco purtroppo

Comunque sono riuscito ad implementare, nella mia mini-stupida applicazione i thread

In pratica ho provato a vedere se si riuscivano ad usare in echo2 i thread e tutto ciò che riguarda la programmazione concorrente che Java mette a disposizione.

Mi sono dedicato ai thread perchè mi sono accorto, leggendo qua e la e provando con il codice, che la classe timer di swing non è disponibile in echo2.

Ma i Thread sì.

Funzionano, ne ho creati due, da far partire in momenti diversi, che aggiornato ogni secondo delle etichette di testo... un thread parte attivo con l'applicazione e s ferma all'atto dell'apertura di una nuova finestra, l'altro viceversa... viene attivato con l'apertura di una nuova finestra e si adormenta alla chiusura della stessa.

Attualmente ho utilizzato un busy waiting per gestire il controllo dello stato dell'applicazione, giusto per provare.
Lo so, non è una soluzione molto corretta, ma qui non mi serviva l'efficienza.
Ma comunque credo sarebbero comunque disponibili i monitor e gli altri sistemi di sincronizzazione di Java, senza alcun problema.

Però è emersa un'altra particolarità di Echo2... che in effetti avevo letto, ma non compreso sino in fondo...
In pratica non tutto cio che il lato server "aggiorna" viene effettivamente aggiornato lato client... la sincronizzazione avviene solo quando lato client succede qualcosa... questo per ridurre lo scambio di messaggi tra client e server per non appesantire la banda

Questo cosa comporta? che per esempio le etichette dei contatori, sebbene i contatori si tengono aggiornati lato server e sono coerenti anche lato client quando vengono visualizzati, romangono FISSI fino a quanto l'utente fa qualcosa lato client... apre una finestra, clicca un pulsante, fa uno scrolling eccetera

Infatti i miei contatori rimangono apparentemente fermi, ma alla prima interazione si aggiornano con i valori che piano piano si erano aggiornati via server...
Questo potrebbe creare dei problemi, ma esiste il sistema per rimediare, modificando la parte client del framework

Comunque, la disponibilità e il funzionamento dei thread, ha messo in risalto che gli eventuali problemi che potrebbero nascere dal bisogno di avere una parte del codice "bloccata" in attesa di qualche interazione, si potrebbero risolvere proprio con l'utilizzo dei thread... che di fatto si posson bloccare su delle risorse e/o condizioni varie con dei monitor o altre soluzioni simili