martedì 30 novembre 2010

SWT CLabel

Come è noto SWT è una libreria che utilizza un approccio totalmente differente rispetto a Swing: in SWT si cerca di utilizzare quanto prima i componenti messi a disposizione del sistema operativo, costruendo poi su questi componenti piu' complessi. Questa differenza è evidente ad esempio se si considera un widget tanto semplice quanto utile: le etichette (label). In Swing una label può essere dotata di una propria immagine, mentre in SWT una Label può avere un testo o una immagine, ma non entrambi. La ragione di ciò è nelle limitazioni del sistema operativo stesso e nell'uso pesante che SWT fa dei componenti nativi. Per ovviare all'inconveniente, SWT utilizza una serie di widget custom i cui nomi tipicamente iniziano con una 'C' (per evitare conflitti nello spazio dei nomi), come ad esempio CLabel. Osservando la gerarchia di una CLabel si nota come questa di fatto erediti da un Canvas, ossia da una zona che può essere disegnata arbitrariamente, mentre la piu' povera Label eredita direttamente da Control, e quindi non prevede personalizzazioni particolari. La differenza di gerarchia fra i due componenti evidenzia l'approccio SWT: Label sfrutta tutte e sole le caratteristiche del sistema operativo, mentre CLabel disegna da se i componenti che servono e li dispone nel modo che ritiene piu' opportuno (immagine a fianco del testo).

venerdì 26 novembre 2010

L'importanza delle convenzioni dei nomi

E' innegabile il valore delle convenzioni applicate ad un progetto software di qualsiasi natura. Le convensioni aumentano la leggibilità delle risorse (tipicamente del codice), semplificano il refactoring, la manutenzione e in generale pongono le basi per l'automazione.
In un progetto database le convenzioni sul nome delle tabelle, procedure, trigger e delle colonne è ancora piu' importante: il database può facilmente crescere a dismisura, arrivando ad avere relazioni intricate fra oggetti diversi. Tuttavia occorre ricordarsi che un DBMS è differente da un sistema OOP, e quindi le convenzioni da usare su uno possono essere differenti e portare a differenti risultati rispetto a quelle usate nell'altro. Si prendano ad esempio i nomi delle colonne: in un sistema OOP i nomi degli attributi degli oggetti potrebbero assumere la stessa convenzione al fine di automatizzare l'accesso alle proprietà stesse, complice anche l'ereditarietà. In altre parole, avendo due oggetti come Person e Department ciascuno dotato di un codice identificativo (ID) e di una descrizione (description) si potrebbe pensare di dotare i due oggetti delle stesse proprietà getID/setID e getDescription/setDescription. Facile, comprensibile, omogeno. 
Nel caso di un database con due tabelle che implementino gli stessi concetti si potrebbe pensare a creare due tabelle con le stesse convenzioni sui nomi: person(ID integer, description text) e department(ID integer, description text). La cosa può a prima vista sembrare naturale, e per molte applicazioni lo è. Tuttavia quando si tenta di mappare i due schemi uno sopra all'altro, si scopre che la convenzione sul nome delle colonne appena scelto produce uno spreco di codice. Si immagini infatti di voler esprimere la relazione fra un reparto e la lista delle persone che vi afferiscono: l'oggetto Department dovrà avere una collection di tipo Person, e nel database ci sarà una tabella di join fra le due di cui sopra. Il problema è che nel join i dati di una tabella devono essere riscritti per non andare in conflitto (ambiguità) con quelli dell'altra tabella, e quindi si potrà avere un solo ID e un solo description nell'output della query, mentre l'altro diventerà ad esempio person_ID e person_description. E perché questo semplice aliasing porterebbe alla scrittura di maggiore codice? Perché i DAO usati per caricare un reparto e una persona fanno affidamento a colonne che si chiamano ID e description, che sono venute a mancare nel join. Come si può risolvere questa problematica? Ci sono tre metodi principali:
  1. si scrive un DAO per il caricamento diretto di un Person, di un Department e di un join fra i due. Ovviamente questa soluzione non è molto pratica;
  2. si creano delle viste su tutte le tabelle in modo che i dati ritornati siano sempre person_ID, person_description, department_ID, department_description sia per le query "semplici" che per i join. Ma questo richiede la scrittura di codice aggiuntivo e non molto utile;
  3. si usa una convenzione differente nei nomi delle colonne: ogni colonna viene nominata con un prefisso che corrisponde al nome della tabella: person( personID integer, personDescription text ) e department( departmentID integer, departmentDescription text ). Così facendo i DAO vengono scritti sempre per colonne che sono univoche nel sistema, anche quando le tabelle vengono messe in join.
L'ultima soluzione, seppur appaia la piu' farraginosa, è quella che porta alla scrittura del minor codice possibile e soprattuto garantisce che se un DAO funziona per la tabella singola funzionerà senza variazione alcuna anche per tabelle in join.

giovedì 25 novembre 2010

Università e professionisti... alcune riflessioni (parte 2)

Dopo una settimana dall'articolo di giornale che mi aveva spinto a scrivere alcune considerazioni sul rapporto fra le Università e il mondo dei professionisti mi sono imbattuto in un altro articolo, questa volta sul Resto del Carlino di Modena, che tratta le proteste contro la "riforma Gelmini" presso il cinema teatro Raffaello.
L'articolo inizia evidenziando come ci sia l'assenza di 110 mila tecnici che le imprese in Italia non trovano, fatto questo che porta ad una semplice tesi: occorre maggiore supporto alla formazione di tali tecnici, ossia maggiore supporto alle scuole e agli atenei, asilo nido dove i giovani talenti possono crescere. Tesi troppo semplice, troppo banale. Anzitutto per formare dei buoni tecnici occorrono dei buoni insegnanti, e ricadiamo nel discorso che ho già affrontato sul collegamento docenti-mondo del lavoro. Dopotutto, quanti docenti si prendono un periodo sabbatico per migliorare e aumentare le proprie competenze? Quanti docenti prendono delle certificazioni? Ora voglio stendere una tesi piu' banale ancora di quella dell'articolo che ho letto: se adesso ci si lamenta per il mancato supporto alla didattica, cosa si è fatto di significativo nella didattica fino ad ora? Ovvero, se mancano 110000 tecnici qualificati significa che le persone formate fino a ieri non sono state abbastanza formate per far fronte alle reali necessità del mondo del lavoro. Quindi non può essere la riforma tanto protestata a creare questo ammanco, semplicemente perché l'ammanco esisteva già da prima. Sicuramente un taglio netto ai supporti non può diminuire la carenza di tecnici, anzi la potrà anche aumentare, ma, continuando sulla linea della "tesi-semplice", il supporto fornito fino ad ora a cosa è servito? Evidente a poco....
E per quale motivo i tecnici non possono essere formati direttamente sul campo? Perché al taglio delle ore di laboratorio non si fa fronte con collaborazioni nel mondo professionale? Ah già, i professionisti non vogliono perché è periodo di crisi...

Ma non è che forse ci si sta lamentando troppo? Non è che in realtà quello che si vuole è un pezzo di carta firmato e timbrato che dia, a tavolino, una esperienza e delle capacità che comunque non si sarebbero acquisite nemmeno con maggior supporto? Non è che è ora di rimboccarsi le maniche e dimostrare che si è in grado di formare realmente dei tecnici, e chiedere a fatto compiuto maggiore supporto? Mi sembra si stia discutendo attorno ad un paradosso: dammi il supporto ($) e ti darò i tecnici. Prima però dimostrami che sei in grado di tirarne fuori almeno uno ben formato, e poi sarò ben lieto di darti il supporto ($) per tirarne fuori 110000.

Ma forse sono sempre io che sono troppo polemico e malizioso...
E a proposito di polemica: complimenti a tutti quegli acculturati che hanno imbrattato la città con uova. Ma forse loro fanno parte dei 110000 che non hanno avuto formazione, e con essa educazione.

RCP: aggiunta della log view ad una applicazione

Grazie alla modularità di Eclipse (e OSGi) è veramente semplice aggiungere una vista di "log" ad una applicazione RCP.
Come prima cosa occorre aggiungere alla applicazione la dipendenza del plugin org.eclipse.ui.views.log.
Successivamente occorre aggiungere il comando al proprio set di menu (o pulsanti o toolbar):
  • selezionare l'elemento dove aggiungere il comando (ad esempio il menu') e aggiungere un nuovo comando con click destro -> New -> Command
  • specificare le informazioni del comando con l'id rappresentato in figura
  •  infine aggiungere al comando un parametro (click destro, New -> Parameter) e specificare l'id della vista da aprire come riportato in figura
 A questo punto l'applicazione visualizzerà il nuovo comando e aprirà la vista dei log dell'applicazione. Il sistema di loggin può essere usato in ogni punto dell'applicazione con il seguente frammento di codice:

ILog logger = Activator.getDefault().getLog();
StringBuffer buffer = new StringBuffer( 100 );
//.....
IStatus status = new Status( IStatus.INFO, 
                             Activator.PLUGIN_ID, buffer.toString() );
logger.log(status);

Nuovi supporti tecnologici per Gigetto

Con l'apertura della nuova stazione di Baggiovara, che sostituisce quella della Bertola, anche le stazioni limitrofe del famoso trasporto ferroviario Modena-Sassuolo (Gigetto) hanno subito un restyling. In particolare la stazione di Casinalbo è ora dotata (o nuovamente dotata) di due nuovi strumenti altamente tecnologici di ausilio ai passeggeri:
  • un potente faro luminoso che sovrasta la zona delle biciclette a noleggio. Chissà, forse qualcuno si è accorto che la stazione era rimasta al buio per troppo tempo ed era quindi diventata facile preda di vandali e maleducati!
  • un nuovo display luminoso che segnala ora, treni in arrivo e relativo ritardo. Peccato che tale tabellone continui a segnare un orario sbagliato e quindi informi in modo totalmente sbagliato gli utenti in viaggio. Avevo già descritto questi pannelli luminosi, che visti in azione mi ricordano tanto la mia prima applet Java che faceva scorrere una scritta sullo schermo spostandola ad intervalli di 1 secondo. Tale tabellone fa la stessa cosa, e non è per niente sincronizzato con i treni in transito o con una delle stazioni di scambio.
Insomma, invece che investire correttamente i soldi in sistemi che funzionano, sembra che il comune (o le ferrovie) intendano spendere i soldi in stupidi giocattoli che non sono di scarso ausilio per i viaggiatori, ma che rimangono facile preda dei vandali.

E come volevasi dimostrare, dopo appena una settimana il pannello luminoso mostra una evidente crepa causata, certamente, da una sassata. E come se non bastasse continua a segnare l'orario sbagliato...

Eclipse RCP Preferences: memorizzare informazioni di login in uno splash screen interattivo

Eclipse RCP mette a disposizione dello sviluppatore un sistema complesso di preferenze che possono essere usate per salvare, ad esempio, informazioni di login. Le preferenze di Eclipse possono essere di due tipi fondamentali:
  • in chiaro
  • cifrate
Le ultime vengono salvate con un meccanismo a keyring e i plugin *.security forniscono tutti gli strumenti necessari al loro utilizzo. Ad esempio org.eclipse.equinox.security.ui permette la memorizzazione nel portachiavi con tanto di dialog per la configurazione del portachiavi stesso. 
Si pone tuttavia un problema per l'utilizzo delle preferenze cifrate: il workspace deve esistere ed essere in esecuzione. Ciò significa che lo sviluppatore ha piu' lavoro da svolgere nel caso in cui le preferenze siano usate da applicazioni RCP headless o, come nel mio caso, da splash screen interattivi (che agiscono prima del workspace stesso).
Qui sotto riporto un esempio di utilizzo di un motore di salvataggio/caricamento dei dati dell'ultimo utente che ha effettuato il login nell'applicazione. In questo caso occorrerebbe salvare i dati in modo cifrato, ma essendo il mio un caso di splash screen interattivo, e trattandosi di dati comunque non fondamentali (poiché nella mia applicazione esistono altri meccanismi di sicurezza), ho deciso di usare per semplicità le preferenze in testo semplice. Da notare che il motore qui sotto proposto estrae ed inserisce i dati in un oggetto User che funge da wrapper per la business logic dietro all'utente stesso.


public class UserPreferencesStorage {

    private String PREFERENCES_USER_ROOT_NODE = "saved-user";
    private String PREFERENCES_USERNAME_NODE  = "username";
    private String PREFERENCES_PASSWORD_NODE  = "password";
    private String PREFERENCES_USER_PK_NODE   = "userpk";

 
    /**
     * Saves the preferences of the provided user.
     * @param user the user that must contain the password and the username to store
     * @return true if the storage has been done
     */
    public boolean saveUserPreferences( User user ) throws BackingStoreException{
 try{
     // get the normal preferences and the scope for this plugin
     IEclipsePreferences preferences = new ConfigurationScope().getNode( Activator.PLUGIN_ID );
     // now get the main node for the configuration storage
     Preferences savedPreferences = preferences.node(PREFERENCES_USER_ROOT_NODE);

     // now store the username and the password
     savedPreferences.put( PREFERENCES_USERNAME_NODE, user.getUsername() ); 
     savedPreferences.put( PREFERENCES_PASSWORD_NODE, user.getPassword() ); 
     savedPreferences.put( PREFERENCES_USER_PK_NODE, user.getPrimaryKey() + "" );  
     
     // flush the storage to ensure everything is written to disk
     preferences.flush();
     
     // all done
     return true;
     
 }catch( BackingStoreException se ){
     // log the exception and do nothing, cannot save
     IStatus status = new Status( IStatus.ERROR,     // severity
      Activator.PLUGIN_ID,      // the id of the application/plug-ing
      "Errore nel salvataggio delle preferenze di login utente",  // message
      se
     );

     throw se;
 }

    }
    
    
    /**
     * Loads a user from the prefences store.
     * @return the user loaded or null
     */
    public User loadUser() throws StorageException{
 // get the normal preferences and the scope for this plugin
 IEclipsePreferences preferences = new ConfigurationScope().getNode( Activator.PLUGIN_ID );
 // now get the main node for the configuration storage
 Preferences savedPreferences = preferences.node(PREFERENCES_USER_ROOT_NODE);
 
 // get the values from the storage
 String username  = savedPreferences.get(PREFERENCES_USERNAME_NODE, "");
 String password  = savedPreferences.get(PREFERENCES_PASSWORD_NODE, "");
 String primaryKey  = savedPreferences.get(PREFERENCES_USER_PK_NODE, "0");
 
 
 // create the user with such values
 User user = new User( Integer.parseInt(primaryKey), username, password );
 
 // all done
 return user;
    }
}

giovedì 18 novembre 2010

Università e professionisti...alcune considerazioni

Disclaimer: come tutti i messaggi qui pubblicati, anche questo rappresenta solamente i miei pensieri e le mie riflessioni, a volte dure, spesso criticabili,
ma basate sulla mia esperienza diretta.

Durante una pausa fra le lezioni di informatica, ho sfogliato il giornale (Corriere della Sera - 13/11/2010) e la mia attenzione è stata attirata da un articolo di Isidoro Trovato che parla di come la Autorità di Vigilanza sui lavori pubblici possa far entrare l'Università nelle gare di appalto a fianco dei professionisti. In poche parole, questo significa che i docenti, i ricercatori e tutto il personale strutturato delle università potrebbe partecipare a gare di appalto pubbliche andando a minare pericolosamente, almeno così sostiene Gianni Rolando (presidente del Consiglio Nazionale degli Ingegneri), le posizioni oggi appannaggio esclusivo dei professionisti. Essendo io ingegnere, ed avendo lavorato per anni all'università, dovrei quindi trovarmi in accordo con Rolando, e invece ritengo che lo sbarramento di questa proposta sia semplicemente ridicolo.

Anzitutto ritengo che le università, in generale, siano troppo slegate dal mondo lavorativo senza quindi avere idea dei problemi che tale mondo sta affrontando. Ci si trova quindi nella condizione nella quale le università lavorano a progetti estremamente innovativi il piu' delle volte spinti non da problemi del mondo lavorativo ma da interessi puramente di ricerca. E per fortuna: sono un forte sostenitore dell'iniziativa individuale. Tuttavia ci si trova anche nella condizione ove, per dimostrare che il proprio lavoro scientifico è valido, si debbano trovare i problemi che la propria ricerca risolve. Ma questo è un modo sbagliato di ragionare: è meglio partire dal problema e trovare la soluzione, piuttosto che avere l'intuizione e cercare  il problema che risolve (o il contesto ove collocarla). Così facendo infatti si rischia solo di produrre soluzioni per un mercato non ancora pronto, e infatti molto spesso i risultati della ricerca scientifica vengono applicati diversi anni dopo al mondo lavorativo. E non si tratta di tempi canonici per la stabilizzazione della soluzione, ma semplicemente di tempi nei quali il mercato non è recettivo poiché occupato a risolvere altri problemi che le università reputano banali e quindi non prendono in considerazione.
Ulteriore ostacolo al dialogo fra il mondo del lavoro e delle università sono, molto spesso, i professori stessi: ogni professore ha un suo ambito di ricerca/interesse e tenta di forzare tale ambito ai suoi studenti, stabilendo spesso anche confini ben marcati che separino la propria ricerca da quella dei colleghi. Ci si ritrova quindi con studenti che svolgono attività di ricerca in un ambito (es. database) senza mettere il becco in altri ambiti (es. sistemi operativi) per volontà dei loro professori. I professori dovrebbero invece mettere a disposizione la loro esperienza affinché gli studenti, preso in carico un problema concreto del mondo del lavoro, possano affrontarlo e risolverlo agevolmente. E in questo modo si avrebbero diversi vantaggi:
  • le aziende acquisterebbero molta fiducia nelle università;
  • gli studenti acquisterebbero fiducia nelle proprie capacità (meglio 10 successi piccoli ma certi che un grande successo non applicabile al mercato);
  • gli studenti troverebbero da lavorare piu' facilmente, avendo maturato una esperienza diretta nel mondo del lavoro;
  • i professori resterebbero automaticamente aggiornati sulle problematiche del mercato.
Attualmente gli atenei informatici, come quello che io ho frequentato, hanno una grossa possibilità per dimostrare le proprie competenze e capacità: l'OpenSource. L'OpenSource è un qualcosa che le università temono molto per due motivi principalmente:
  • rilasciare un progetto come OpenSource significa dare al mondo (e quindi ad altre università) i propri sforzi di ricerca;
  • un progetto OpenSource potrebbe vedere la partecipazione di altri professionisti o università che mostrino una superiorità schiacciante in tale ambito.
Spaventati quindi dal vedersi rubare i propri sforzi o dal fare figuracce planetarie, le università preferiscono rimanere tranquillamente nascoste dietro qualche deliverable di qualche progetto strano che non permette la visione del codice e dei prototipi prodotti. Ovviamente non tutti gli atenei sono così, e sempre di piu' si evidenziano facoltà che abbracciano lo spirito OpenSource e riescono ad affermarsi nel panorama accademico e professionale. Tuttavia in Italia la paura è ancora alta, almeno questa è l'impressione che ho avuto girando per i vari atenei. Va comunque notato che, figuraccia o meno, il confronto è sempre un possibile spunto di crescita, e che esistono licenze e strumenti per tutelare il proprio lavoro. 

Torniamo ora all'argomento di discussione specifico: il possibile contrasto fra i professionisti e gli accademici. Di cosa dovrebbero avere paura i professionisti? Dopotutto, la loro professionalità non dovrebbe essere messa in discussione da un qualche professore o studente che si presenta sul mercato: quello che conta, che si tratti di professore, studente, o libero professionista, è l'esperienza e l'abilità, due qualità che non possono essere conquistate stando  solo dietro ad una cattedra o solo nel mondo del lavoro. Io, da ingegnere, non temo il confronto onesto con un altro ingegnere, e poco mi importa sia un docente, uno studente o un professionista: per quello che riguarda il confronto è solo un mio "sfidante". Quali scenari dunque si prospettano e perché spaventano tanto i professionisti? Io riesco ad individuare queste possiblità:
  • l'università inonda il mercato con personale a basso costo e alta qualità: il prezzo dei professionisti è costretto ad abbassarsi di conseguenza per poter reggere la concorrenza, e questo è un bene per chi richiede il servizio;
  • l'università inonda il mercato con personale a basso costo e bassa qualità: è evidente che tale personale non sarà in grado di fornire un servizio alla pari di quello di un professionista esperto, e quindi tale categoria non ha nulla da temere da questo confronto. Va inoltre notato che un professionista non può tutelarsi da questa problematica che non è infatti legata al mondo accademico.
  • l'università inonda il mercato con personale ad alto costo e di alta qualità: in questo caso i professionisti occupano la seconda posizione nelle scelte mission critical, ma il loro costo inferiore li rende una scelta papabile per tutti gli altri casi.
  • l'università inonda il mercato con personale a basso costo, bassa qualità da affiancare a personale professionale: in questo caso si assiste alla formazione di un nuovo professionista a "discapito" di un altro professionista. Ma occorre ricordare che quest'ultimo sarà stato a sua volta formato (si spera) a "discapito" di un docente universitario...
Francamente penso che una persona competente e preparata non debba temere il confronto con un'altra persona competente e preparata, poiché in un confronto onesto è giusto che "vinca" la persona migliore. Quindi impedire il confronto a priori è una scelta sbagliata e, soprattutto, che da una impressione sbagliata sulla categoria dei professionisti, che appaiono ora ai miei occhi come un branco di baroni che vogliono proteggere il proprio feudo. E non ho usato il termine "baroni" a caso: ritengo che dall'altro lato esista un altro gruppo di baroni impegnati a proteggere la propria scrivania. Ebbene se l'apertura al mondo del lavoro destabilizzera il loro regno, a maggior ragione ben venga l'iniziativa di cui si sta discutendo. DI baroni devono governare un impero proporzionale alle proprie capacità.

Anni fa una protesta analoga venne fatta dal lato accademico, spaventato dal possibile ingresso di industrie e professionisti nel loro "regno". E anche in quella occasione io evidenziai i miei dubbi su tanta rigidità: dopotutto aprire l'università all'industria significa, come già detto sopra, aprire la strada a nuovi posti di lavoro. Rolando, che a difesa della sua tesi sottolinea il periodo di crisi del mercato, dovrebbe tenere in considerazione anche questo fattore: dare spazio di lavoro ai giovani significa aumentare l'occupazione, non aumentare la disoccupazione dei professionisti. E quindi mi viene solo da ribadire come ognuno dovrebbe smettere di guardare al prioprio orticello, ma assumere una visione piu' ampia della questione.

Come riflessione conclusiva mi viene in mente che, se entrambe le parti, in tempi e con motivazioni diverse, non vogliono mischiarsi, forse il vero problema non è tanto sulle competenze, sulle capacità, sulla professionalità, ma sulla mancanza di un confronto onesto che tuteli entrambi i lati affinché solo chi è meritevole possa avere successo.

Ma forse sono io che non ho ben capito il reale problema....

    martedì 16 novembre 2010

    SWT Virtual Table: problemi di sorting

    Le tablle Virtual in SWT sono sicuramente un componente tanto potente quanto fragile, lo dimostrano due problemi che ho incontrato nello sviluppo di una applicazione che mi hanno fatto deistere dal continuare ad usarle, almeno per il momento. Il mio ovviamente si tratta di un caso particolare: non sempre è possibile rinunciare alle tablle virtual a favore di quelle normali!
    Il primo problema riguarda l'update degli indici: sembra ci sia un bug che richiede l'update di indici fuori dallo schermo, con conseguente caricamento dei dati necessari, e si può facilmente intuire come in una applicazione database oriented (come la mia) questo sia un consumo eccessivo di risorse che non giustifica l'uso di SWT.VIRTUAL.
    Il secondo problema riguarda il sorting effettuato tramite comparators: se la tabella viene gestita come Virtual (anche se in effetti viene usata come tabella normale), il sistema potrebbe passare un elemento null al metodo di comparazione del Comparator. Il problema non è tanto difendersi da un oggetto null in ingresso, cosa sicuramente banale, ma il fatto che una comparazione fra due entità di cui una null non può essere fatta, poiché questo impedisce la determinazione del corretto indice di inserimento nella table viewer.

    sabato 13 novembre 2010

    OpenSolaris promo t-shirt

    Qualche giorno fa ho comprato una delle magliette promozionali di OpenSolaris. Seppur vero che il destino di OpenSolaris è ormai irrimediabilmente segnato, è altrettanto vero che le magliette promozionali erano dei veri e propri pezzi d'arte!

    venerdì 12 novembre 2010

    Eclipse Labs

    Esiste un progetto, denominato Eclipse Labs, che permette a sviluppatori di progetti Eclipse-related di ottenere un maggiore riconoscimento dei loro sforzi. Gli Eclipse Labs si appoggiano a Google Code, e quindi sono un sistema di hosting dei progetti via SVN/Mercurial (vivamente consigliato il secondo, anche se era preferibile Git) su server Google. I progetti che entrano in Eclipse Labs non sono a tutti gli effetti dei progetti della Eclipse Community, ad ogni è possibile dare al proprio progetto un maggior rilievo nell'ecosistema Eclipse mantenendo all'interno degli Eclipse Labs invece che su un altro sistema di hosting non correlato ad Eclipse.

    mercoledì 10 novembre 2010

    Nebula download corrotto

    E' ormai da un paio di settimane che il sito del progetto Nebula, una serie di widget addizionali basati su SWT, non permette il download dei jar in fase di incubazione riportando uno spaventoso messaggio circa la corruzione di tutti i build del progetto stesso.



    Quello che c'è dietro a questo messaggio di errore viene spiegato in un messaggio sul forum ufficiale di Nebula: un build server è andato in crash, causando l'errore nella ricostruzione dei pacchetti binari. Tutto questo succede mentre il progetto sta migrando la propria storia su un altro sistema, ecco quindi che si è preferito terminare la migrazione piuttosto che spendere tempo nella ricostruzione degli archivi legacy.

    RCP: ottenere le informazioni di plugin a run-time (immagini e versione del prodotto)

    Capita spesso di dover accedere a delle informazioni di definizione di un plugin RCP a run-time. Gli esempi piu' ricorrenti sono le immagini associate ad una applicazione RCP e i dati del bundle che definisce l'applicazione stessa (ad esempio il numero di versione). RCP mette a disposizione una serie di facilities per ottenere tali informazioni.
    Il primo passo consiste nell'ottenere una istanza di IProduct, dal quale si può estrarre il defining bundle e da questo la lista delle immagini configurate nel file plugin.xml. Tale lista è in realtà una stringa unica con tutte le immagini alle varie dimensioni (16x16, 32x32, 48x48, ecc.) dalla quale occorre estrarre la lista effettiva dei percorsi (relativi al bundle) delle immagini. Avendo ottenuto la lista delle immagini è possibile inserirle nella shell corrente (ad esempio uno splash screen). Il seguente blocco di codice riassume i passi da fare:

            // get the product for the running instance
            IProduct product = Platform.getProduct();
           
            // get my shell
            Shell myShell = ...
           
            // the product can be null if the running instance is launched
            // as an eclipse application (e.g., during the development)
            if( product == null )
                return;
           
            // get the bundle symbolic name
            String bundleID = product.getDefiningBundle().getSymbolicName();
            // get the array of the application icons (defined thru the product)
            // the method will return a single string with the list of images
            // used at different sizes (16x16, 32x32, 48x48 and so on). The list is
            // comma separated, so I need to extract every single item.
            String imagePaths = product.getProperty( 
                                            IProductConstants.WINDOW_IMAGES );
            List imagePathList = new LinkedList();
            StringTokenizer commaTokenizer = new StringTokenizer(imagePaths, ",");
            while( commaTokenizer.hasMoreTokens() )
            imagePathList.add( commaTokenizer.nextToken() );
           
            // now that I've got the list of image paths (separated) 
            // I can create every
            // single image using an ImageDescriptor
            Image[] windowImages = new Image[ imagePathList.size() ];
            for( int i = 0; i < imagePathList.size(); i++ ){
               ImageDescriptor currentDescriptor =                    
                   AbstractUIPlugin.imageDescriptorFromPlugin(    bundleID, 
                                                    imagePathList.get(i) );
                   windowImages[ i ] = currentDescriptor.createImage();
            }
           
            // now set the images for this window
            myShell.setImages( windowImages );




    Analogamente, se si volessero ottenere informazioni circa la versione e il nome dell'applicativo si puo' usare il seguente pezzo di codice:


    Bundle definingBundle = product.getDefiningBundle();
    Label valueLabel = new Label(  definingBundle.getSymbolicName() );
    Label versionLabel = new Label( definingBundle.getVersion().toString() );

    o se si vuole cambiare il titolo della finestra principale del workspace affinché rifletta tali informazioni è sufficiente, nel metodo ApplicationWorkbenchWindowAdvisor.preWindowOpen() il seguente blocco di codice:

       // get the window configurer object
        IWorkbenchWindowConfigurer configurer = this.getWindowConfigurer();

       
       
        // set the title of the window
        StringBuffer title = new StringBuffer( 100 );
        title.append( "My App" );    // the fixed part of the title
       
        // get the information from the product
        IProduct product = Platform.getProduct();
        if( product == null )
            title.append( " [Eclipse Application - Development]" );
        else{
            title.append( " [RCP Product -" );
            title.append( product.getName() );
            title.append( " ~~ " );
           
            // get some information from the bundle
            Bundle definingBundle = product.getDefiningBundle();
            title.append(" ID: " );
            title.append( definingBundle.getSymbolicName() );
            title.append(" ~~ Ver.: " );
            title.append( definingBundle.getVersion() );
        }
       
        // set the real title
        configurer.setTitle( title.toString() );

    martedì 9 novembre 2010

    KMail: migrare le impostazioni delle cartelle

    La mia posta elettronica vanta un numero sterminato di cartelle e di filtri che uso per gestire un altrettanto vasto numero di iscrizioni a mailing lists. Una cosa molto gradevole di KMail è che è un client di posta furbo: quando si migra da un computer ad un altro o da una versione all'altra, spostare le cartelle di posta e i file di configurazione è sufficiente per migrare l'intera posta comprensiva di account, regole e filtri.
    Tuttavia KMail non è così furbo da aggiustare anche gli account associati alle cartelle di posta, e quindi a seguito della migrazione un nuovo messaggio creato dentro ad una qualsiasi cartella viene editato con l'account di default. Ovviamente è possibile sistemare manualmente il problema, ma nel mio caso questa soluzione mi avrebbe portato via troppo tempo. 
    Ho quindi deciso di studiare come KMail associa le identità degli account alle cartelle e di creare un banale programma che, in modo molto goffo, aggiusti le cose per me.
    KMail memorizza le identità degli account di posta nel file emailidentities, e ogni identità in tale file contiene un valore identificativo univoco come proprietà dal nome uoid. Ogni identità ha quindi una linea del tipo
    uoid = 1234556
    con il valore numerico che cambia a seconda dell'identità. Il primo passo è quindi quello di recuperare lo uoid associato ad un account di posta (nel mio caso non ho account duplicati su varie identità, altrimenti il test dovrebbe essere piu' complesso).
    A questo punto, nel file di configurazione principale di KMail, kmailrc, occorre analizzare ogni sezione di ogni cartella, e infatti in essa si troverà una linea che indica se occorre usare l'identità di default (UseDefaultIdentity = true) e una linea che indica l'identità da usare al suo posto (Identity = uoid). Quindi individuata la sezione corrispondente alla cartella che si vuole manipolare, è sufficiente inserire le due righe di cui sopra specificando l'identità da usare e facendo in modo che l'identità di default risulti disabilitata per tale cartella.
    Si può fare ancora di piu': nel mio caso le cartelle corrispondenti a mailing list sono, con grande fantasia, tutte raggruppate sotto un'unica cartella dal nome Mailing List. Ebbene, kmailrc contiene nel nome della sezione il percorso completo della cartella, incluso il nome del padre della cartella. Quindi nel mio caso, le cartelle da manipolare non devono essere specificate manualmente ma possono essere ricavate automaticamente usando il prefisso Mailing List.
    Di seguito presento lo script Perl che realizza quanto descritto sopra. Il suo utilizzo, da linea di comando, prevede il passaggio di due argomenti: il percorso al file di configurazione principale kmailrc e un indirizzo di posta da usare per ottenere l'identità dell'account. L'output è un file di configurazione differente, denominato kmailrc.new da sostituire, previo controllo, a quello originale.


    #!/usr/bin/perl
    
    open( KMAILRC, "<$ARGV[0]" )       || die("\nCannot open the specified kamilrc file\n$!\n");
    open( EMAILIDENTITIES, "<$ARGV[1]")|| die("\nCannot open the email identities file\n$!\n");
    open( NEWCONFIG, ">kmailrc.new" )  || die("\nCannot open the new configuration file\n$!\n");
    
    
    $emailAddress = $ARGV[2];
    $IDENTITY = undef();
    
    # first step: find the identity id
    while( ($line = ) && (! defined($IDENTITY) ) ){
        chomp( $line );
        if( $line =~ /$emailAddress/ ) {
     print "\nFound e-mail addrress $line";
     while( ($line = ) && (! defined( $IDENTITY ) ) ){
         if( $line =~ /uoid/ ){
      $line =~ s/(uoid=)(.*)/$2/;
      $IDENTITY = $line;
      print "\nFound an identity uoid = $IDENTITY\n";
      
         }
     }
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    $FolderKey = $ARGV[3];
    
    while( $line =  ){
        chomp( $line );
    
        if( $line =~ /\[Folder-\.$FolderKey/ ){
     chomp( $line );
     print NEWCONFIG $line , "\n";
     print "\nFound folder $line\n";
     $doneThisFolder = "";
    
     while( ($innerLine = ) && (! $doneThisFolder ) ){
         chomp( $innerLine );
    
         if ( $innerLine =~ /UseDefaultIdentity/ ){
      print NEWCONFIG "UseDefaultIdentity=false\n";
      print NEWCONFIG "Identity=$IDENTITY\n";
      $doneThisFolder = "true";
         }
         elsif( $innerLine =~ /Identity/ ){
      # print nothing, it has already be printed in the 
      # UseDefaultIdentity identity
         }
         else{
      print NEWCONFIG $innerLine , "\n";
         }
         
     }
    
        }
        else{
     print NEWCONFIG $line , "\n";
        }
        
    }

    lunedì 8 novembre 2010

    Programma PGDay 2010

    E' disponibile il programma del PGDay 2010.
    Come si evince dal programma stesso, il PGDay di quest'anno avrà un elevato contenuto tecnico e i partecipanti avranno l'occasione di essere a diretto contatto con alcune delle principali figure dello sviluppo PostgreSQL nel mondo.