giovedì 30 ottobre 2008

Importazioni immagini in PostgreSQL: un semplice script shell

Qualche giorno fa mi sono trovato a dover inserire una serie di immagini di persone in un database aziendale, ovviamente facendo corrispondere ciascuna persona alla propria immagine. Siccome il software che sto sviluppando non permette (ancora) di associare ad una persona la propria immagine, mentre consente di visualizzarla, ho deciso di caricare le immagini da linea di comando. Il problema era come mappare ogni immagine con la relativa persona. Purtroppo le immagini erano tutte nominate nella forma nome_cognome, e quindi l'unica strada era quella di sfruttare i relativi dati nel database. Ovviamente questo rischia di creare problemi in casi di omonimia, ma dopotutto è più rapido correggere alcune immagini sbagliate che inserirle una per una a mano!
Ho quindi creato il seguente script shell che fa il lavoro sporco:

#!/bin/bash

SQL_FILE="immagini.sql"
echo "BEGIN;" > $SQL_FILE

for img in *.tif
do
echo "\t==== Processo immagine $img ==="
NAME=`basename $img .tif`
NAME=`echo $NAME | sed 's/_N//;'`
NAME=`echo $NAME | sed 's/_B//;'`
NAME=`echo $NAME | sed 's/_[1-9]//;'`
NAME=`echo $NAME | tr [:upper:] [:lower:]`

echo "=> $NAME"
FILE_PNG=$NAME.png
FILE_PNG_1=$NAME_1.png

# conversione immagine
if [ ! -f $FILE_PNG ]
then
convert $img -quality 100 $FILE_PNG_1
convert $FILE_PNG_1 -resize 30% $FILE_PNG
fi

# estraggo nome e cognome
sql_surname=`echo $NAME | awk -F_ '{print $1;}'`
if [ -z "$sql_surname" ]
then
sql_surname="XXX"
fi

sql_name=`echo $NAME | awk -F_ '{print $2;}'`
if [ -z "$sql_name" ]
then
sql_name="YYY"
fi

CURRENT_DIR=`pwd`

echo -en "UPDATE person SET image = lo_import('$CURRENT_DIR/$FILE_PNG') WHERE " >> $SQL_FILE
echo -en " (lower(name)='$sql_name' AND lower(surname)='$sql_surname') " >> $SQL_FILE
echo -en " OR " >> $SQL_FILE
echo -en " (lower(surname)='$sql_surname' AND (SELECT COUNT(surname) FROM person WHERE lower(surname)='$sql_surname') = 1 )" >> $SQL_FILE
echo ";" >> $SQL_FILE

done


echo -en "\n\nCOMMIT;\n" >> $SQL_FILE

Come si può notare prima faccio un po' di pulizia sul nome del file (le immagini erano tutte .tif) e ottengo la stringa nome_cognome, e procedo ad una conversione nel formato richiesto dalla mia applicazione (png). Successivamente estraggo i singoli pezzi (nome e cognome) e costruisco una stringa di comando SQL per l'update di un campo blob (image) della tabella corrispondente (person). La query SQL effettua un update dove trova corrispondenza di nome e cognome o dove trova anche solo il cognome (a patto che ve ne sia solo uno). Tutte le query SQL vengono salvate in un file che viene poi lanciato da un terminale psql. Da notare che tutti gli inserimenti avvengono all'interno di una transazione, per evitare problemi di incoerenza (o si caricano tutte le immagini o nessuna).

mercoledì 29 ottobre 2008

Explain su tabella vuote

Mi sono accorto per caso, preparando le slide del LinuxDay 2008, che l'EXPLAIN di PostgreSQL si comporta in modo strano quando la tabella è vuota.
Ad esempio:

# create table test(id serial, descrizione character varying(20));

# explain select * from test;
QUERY PLAN
--------------------------------------------------------
Seq Scan on test (cost=0.00..18.80 rows=880 width=62)

# analyze verbose test;
INFO: analyzing "public.test"
INFO: "test": scanned 0 of 0 pages, containing 0 live rows and 0 dead rows; 0
rows in sample, 0 estimated total rows
ANALYZE

# explain select * from test;
QUERY PLAN
--------------------------------------------------------
Seq Scan on test ?(cost=0.00..18.80 rows=880 width=62)
(1 row)

# select count(*) from test;
count
-------
0
(1 row)

quindi la tabella è vuota, e anche se ci si esegue un ANALYZE su di essa, l'ottimizzatore continua a sostenere che 880 righe possono essere ottenute da essa. Mi sono poi accorto che nel caso di tabella vuota non viene inserita nessuna statistica in pg_stats, e quindi l'ottimizzatore non ha modo di capire che la tabella sia vuota (o meglio potrebbe capirlo solo dal fatto che non esiste una statistica in pg_stats, ma questo può anche ricondurre ad un caso di tabella non analizzata). L'ottimizzatore tenta quindi di fare una stima delle tuple che potrebbe essere contenute nella tabella, dipendentemente dalla dimensione della pagina dati e dalla dimensione della tupla stessa.

Disabilitare quell'odioso beep delle console dei server....

Quando mi trovo a lavorare direttamente sulla console di un server più volte vengono rimproverato dal beep della console stessa, che arriva quasi ad infastidirmi. E' possibile disabilitare il suono del terminale con il comando:

setterm -blength 0

e le orecchie si riposano!

martedì 28 ottobre 2008

lunedì 27 ottobre 2008

PostgreSQL @ LinuxDay 2008

Sabato si è svolto il LinuxDay, e io ho avuto l'opportunità di partecipare all'edizione di Modena presentando PostgreSQL e ITPug. Anzitutto mi complimento con i ragazzi di Conoscere Linux per l'ottima organizzazione dell'evento, e ringrazio il loro presidente, Giordano Lanzi, per avermi dato l'opportunità di partecipare nonostante lo scarso preavviso. Ringrazio anche il mio amico Luca "Marty" per avermi prestato il suo portatile per la presentazione, visto che il mio soffre di qualche problema all'uscita video.
Il talk ha avuto una buona partecipazione e un buon interesse, diciamo che sono riuscito a dare una buona visione del perché PostgreSQL è un database di classe enterprise. Il talk è iniziato con un po' di storia del progetto e qualche parola sulla community PostgreSQL e ITPug, dopodiché è passato all'installazione e uso basilare del sistema, per poi passare ad alcuni meccanismi interni (layout su disco, cataloghi, statistiche, WAL, PITR, MVCC, lock).

.pgpass e nomi host in pg_dump

Ho scoperto quasi per caso che l'utility pg_dump quando usa il file .pgpass per l'accesso trasparente ad un database non tiene in considerazione di eventuali nomi host o alias. In altre parole, se all'interno del file .pgpass l'host viene specificato con un indirizzo IP, nella riga di comando pg_dump non si può specificare il nome host, poiché il file .pgpass viene testato con una comparazione secca sul testo che compare nella posizione dell'host e il testo passato sulla riga di comando.

sabato 18 ottobre 2008

PGDay 2008: giorno 2

Anche la seconda giornata del PGDay 2008 si è rivelata un successo. Alla fine della manifestazione tutti i partecipanti si sono congratulati con gli organizzatori per l'ottimo livello dei talk e dei servizi messi a disposizione. Giusto per dare qualche numero, si calcola che i visitatori totali siano stati 171!!!!!

L'assemblea ITPug è stata seguita con attenzione e interesse anche dai non soci, e molte persone si sono dette interessate ad iscriversi quanto prima. E' parso evidente l'interesse comune nel promuovere PostgreSQL in Italia, e tutti vogliono poter fare il loro pezzetto per far guadagnare a PostgreSQL punti in più.

Sono stato fermato parecchie volte da gente che continuava a chiedermi informazioni su Java, sul driver JDBC e con alcuni di loro ho anche potuto lanciarmi in riflessioni filosofiche su PostgreSQL stesso.

Sono soddisfatto dei talk e dei corsi che ho seguito, l'ultimo dei quali, Partitioning di Enrico, ha scatenato una interessantissima discussione.

Sono contento di aver avuto l'opportunità di far nuovamente parte di un evento così grande, e sono contento che i soci di ITPug e gli altri volontari abbiano avuto fiducia nella realizzazione del PGDay e si siano impegnati per farlo riuscire al meglio (e meglio di così penso fosse realmente difficile!) nonostante qualche preoccupazione espressa in passato. E a tutti i volontari va un grossissimo ringraziamento per i loro sforzi.

Sono inoltre molto contento che i ragazzi di psql.it abbiano partecipato attivamente alla conferenza, mostrando un sincero interesse per il lavoro svolto da ITPug in questo suo primo anno di vita.

Ho ritrovato in questi giorni la cordialità, la curiosità e la voglia di collaborazione che sembra caratterizzare tutti gli utenti di PostgreSQL.

Un'esperienza veramente appagante.

venerdì 17 ottobre 2008

PGDay 2008: giorno 1

Ci siamo, il PGDay 2008 è in corso, oggi si è svolto presso la bellissima sede della Monash University di Prato il primo giorno della conferenza.
Sono rimasto piacevolmeten soddisfatto dall'affluenza, maggiore dell'anno scorso, e dall'interesse crescente per PostgreSQL e per l'associazione ITPug.
Questa prima giornata è stata un'ottima occasione per rivedere gli amici e colleghi di ITPug, nonché amici e colleghi volontari di altre associazioni e comunità. Nella mattina si è svolto il keynote di Dave e Magnus, seguito poi dall'inizio dei talk. La sessione italiana si è aperta con un talk molto interessante sulla gestione di informazioni spaziali di cartelli e insegne, proseguendo poi con altri validi talk relativi al mondo GIS. Non ho potuto purtroppo seguire tutti i talk perché a fine mattina ho tenuto, assieme ad Enrico, la prima parte del corso di connettività PostgreSQL da diversi linguaggi. A me chiaramente è toccata la parte Java, e devo dire che ho visto un interesse maggiore rispetto all'anno scorso, forse anche per la drastica riduzione dei lucidi e degli argomenti trattati, nonché per una sostanziale semplificazione degli esempi che hanno probabilmente reso il corso più comprensibile. La parte del corso Java è terminata nel primo pomeriggio, dopo la foto di gruppo e un ottimo pranzo gustato sulla terrazza della sala Veneziana assieme agli amici volontari del PGDay. Il pomeriggio poi è passato veloce seguendo un altro corso sulla migrazione da MySQL a PostgreSQL (tenuto da Gabriele) e la presentazione al pubblico di ITPug.
L'aperitivo offerto da EnterpriseDB e la pizza con gli amici (vecchi e nuovi) ha concluso la prima giornata della conferenza.

Sono molto contento che la conferenza stia procedendo così bene, anche se un po' si sente la mancanza di alcuni nomi illustri dell'anno scorso...non che i nomi importanti manchino, anzi! E poi quest'anno con la developer room permanente il livello tecnico e il numero di sviluppatori è veramente alto.

mercoledì 15 ottobre 2008

Caricare immagini da un database

Il seguente metodo legge una immagine memorizzata come BLOB in un database PostgreSQL (tipo di dato OID) e la converte in un'immagine Java.
L'idea è quella di avere una classe Person che memorizza le informazioni di una persona, fra le quali la propria immagine. La classe mantiene una variabile image che funge da cache per l'immagine della persona: se l'immagine è già stata caricata essa non viene riletta dal database per motivi di efficienza.
Il metodo getImage() carica l'immagine dal database. Al di là delle operazioni preliminari, specifiche di un framework e comunque riconducibili facilmente a JDBC, il metodo ottiene il ResultSet relativo all'immagine, e da questo preleva il BLOB dell'immagine. Tale blob viene poi usato per ottenere lo stream di input dell'immagine. Tale stream viene passato alla classe ImageIO, utilizzata appunto per caricare una immagine da uno stream di byte.

   
/**
* The image of this person.
*/
private Image image = null;

/**
* Returns the image of this person.
* @return the image of the person
*/
public synchronized Image getImage(){
// do I have already loaded an image?
if( this.image != null )
return this.image;

// if here the image is not yet loaded, so load it from the database
try{
Logger.debug("Start loading the image of the person " + this.personPK);

String sql = "SELECT image FROM person WHERE personpk=? AND image IS NOT NULL";
Object params[] = {this.personPK};
Database database = Database.getInstance();
database.initTransaction();
ResultSet rs = database.query(sql, params);

while( rs != null && rs.next() ){
Blob imageBlob = rs.getBlob("image");
long size = imageBlob.length();

byte[] imageBytes = imageBlob.getBytes(1, (int) size);
Logger.debug("the image has size in bytes: " + size);
this.image = ImageIO.read( new ByteArrayInputStream(imageBytes));


}

// all done
Logger.debug("end loading image");
database.commit();




return this.image;

}catch(DatabaseException e){
Logger.exception("Exception caught while loading a person's image", e);
return null;
} catch (SQLException e) {
Logger.exception("Exception caught while loading a person's image", e);
return null;
} catch (IOException e) {
Logger.exception("Exception caught while loading a person's image", e);
return null;
}

}

lunedì 13 ottobre 2008

Un matrimonio da record

I due arcieri coreani Park e Park si sposeranno questo Dicembre. Visto che sono due fra i più forti arcieri al mondo (o meglio, lei è sicuramente la più forte al mondo) e che entrambi hanno preso l'argento individuale alle ultime olimpiadi, da questo matrimonio non può che nascere un super-arciere!!

venerdì 10 ottobre 2008

Strazio o disperazione?

Dopo la mia avventura di non-ricarica della tessera del treno (vedere Servizio o Strazio) ho vissuto l'ennesima situazione ridicola, a conferma ancora una volta di come non vi sia nessun interesse nel mantenere efficiente il servizio ferroviario locale.
Ieri, avendo la tessera ormai scarica, ho deciso di sfruttare la coincidenza di Formigine per scendere dal treno e ricaricare la tessera, risalendo poi regolarmente sul treno. E' una cosa che ho già fatto almeno tre volte in passato, sfruttando il fatto che il treno rimane fermo a Formigine per diversi minuti (aspettando quello in arrivo da Modena per lo scambio) e considerando che non vi è altro posto nelle vicinanze ove ricaricare la tessera. Arrivato a Formigine mi catapulto quindi giù dal treno, avviso il controllore delle mie intenzioni e gli chiedo di aspettare a ripartire; quest'ultimo annuisce. Corro verso la biglietteria e arrivato là chiedo che mi venga ricaricata la tessera. Il capostazione, in evidente stato di panico, mi dice che devo aspettare perché deve controllare l'arrivo del treno di Modena. Arriva il treno di Modena e il capostazione, anziché affrettarsi a ricaricarmi la tessera, con tutta calma inizia a scrivere dei dati su un registro. Io, già spazientito, gli faccio notare come debba risalire sul treno per Modena, e questi in tutta calma mi risponde che non faccio più in tempo perché il treno stava partendo. Guardo fuori e vedo attraverso i vetri del treno fermo sul binario il mio che si allontana. Apriti cielo!
Infuriato come non mai faccio notare al capostazione come avessi chiesto al controllore di aspettarmi, e di come questo servizio (ferroviario) sia veramente pessimo. Il capostazione inizia a farfugliare di come stia facendo del suo meglio e di come io avessi potuto prendermi un minuto in più, arrivare prima, e ricaricare la tessera con calma. Sempre più arrabbiato spiego al capostazione di come la sera prima mi sia stata rifiutata la ricarica per problemi di orario, e questi, sempre con calma, mi dice che sono le regole. Bene: allora che senso ha far circolare i treni fino a tardi (circa le 22) se la gente che torna a casa non ha il servizio di biglietteria? Ma inutile dire che il capostazione non capisce le mie argomentazioni, e continuando nella discussione mi rendo pure conto che non ha capito da dove provenissi: era infatti convinto fossi a terra e che dovessi salire sul treno per Modena dalla stazione di Formigine, non che fossi sceso dal treno diretto a Modena per risalirci. Gli rispiego la situazione e gli chiedo cortesemente di fornirmi il nome del controllore del treno. A questo punto il capostazione si rende conto del problema e, con il capo cosparso di cenere, mi conferma il cattivo comportamento del controllore, che quanto meno avrebbe dovuto informarmi di non scendere per problemi di tempo. Chiama quindi la stazione di Modena, si fa dire il nome del controllore e chiama poi quest'ultimo per sgridarlo sul suo comportamento. Chiaramente il controllore risponde nell'unico modo possibile: pensava che fossi già risalito. Eh si, perché di persone con un libro sottobraccio e lo zaino sulle spalle alle 18.30 nella stazione di Formigine ce ne sono tante...io non ne ho vista neanche una. E forse controllare che io fossi realmente salito o guardare dentro alla biglietteria per vedere se fossi ancora là era troppa fatica anche per il controllore.
Ad ogni modo non c'è niente da fare, se non aspettare il treno dopo (che passa con frequenza di un'ora) e fare reclamo...ma di sapere il nome del controllore non c'è modo, il capostazione si rifiuta di darmelo.

Dopo questa sfuriata in stazione mi sono rimboccato le maniche e sono tornato a casa a piedi, impiegandoci circa 30 minuti. Capisco benissimo che il treno, essendo un servizio pubblico, non può attendere i miei comodi (altrimenti sarebbe un taxi), ma effettivamente il controllore poteva anche fermarmi e il capostazione poteva servirmi subito. A parte questo, quello che mi fa realmente arrabbiare è che io ho perso il treno per voler essere onesto, ossia ricaricare la tessera per poter fare il biglietto. Chi me lo ha fatto fare? Non potevo far finta di nulla, rimanere a bordo seduto a leggere, e nel caso di un controllo dire che avevo la tessera esaurita e la stavo per ricaricare, o meglio ancora che la macchinetta non funzionava (scusa molto in voga fra gli extra-comunitari)? Dopotutto da Settembre ad oggi (circa 30 viaggi) ho avuto solo tre controlli (ossia il 10%). Come ho detto con il capostazione, che razza di servizio stanno mantenendo?



Ah, questa mattina ho potuto fare il biglietto regolarmente....

giovedì 9 ottobre 2008

Servizio o strazio?

Ieri sera mi sono recato in stazione a Formigine per ricaricare la mia tessera del treno, ebbene non mi è stato possibile ricaricarla perché oltre le 19.30 il servizio di ricarica non è più attivo. Chissà che senso ha far circolare i treni fin verso le 21 se i servizi di biglietteria/ricarica sono sospesi dalle 19.30. Una persona che si accorga, rientrando a casa la sera, di avere la tessera scarica e decida di fermarsi in stazione (perché è di strada) per ricaricarla si sentirà rispondere, come è successo a me, che deve ripassare il giorno seguente in un orario differente.
E pensare che un paio di mesi fa l'avevo ricaricata proprio prima di andare in piscina, è forse questo un nuovo disservizio del sistema ferroviario locale?

Inizio ad essere fermamente convinto che la regione voglia far chiudere questa tratta di treno. Da quando è subentrata la regione non ci sono più controlli (non che prima abbondassero, ma qualcuno c'era), gli orari sono cambiati, la frequenza dei treni diminuita, le fermate ridotte e...non si può caricare nemmeno la propria tessera.

Finirà che riprenderemo tutti la macchina, e che continueremo a lamentarci del traffico e dell'inquinamento.

venerdì 3 ottobre 2008

Problema lettura file di proprietà in Eclipse

Qualche giorno fa ho ripristinato il workspace di Eclipse 3.3 per una nuova installazione di Eclipse 3.4, ma il riavvio di un progetto Java mi ha causato qualche problema. In particolare mi sono trovato la seguente eccezione:

java.lang.ClassCastException: org.apache.xerces.dom.DeferredCommentImpl cannot be cast to org.w3c.dom.Element
ERROR - Cannot load properties from the specified file <./conf/login.prop> java.lang.ClassCastException: org.apache.xerces.dom.DeferredCommentImpl cannot be cast to org.w3c.dom.Element

at java.util.XMLUtils.importProperties(XMLUtils.java:97)
at java.util.XMLUtils.load(XMLUtils.java:69)
at java.util.Properties.loadFromXML(Properties.java:852)
at g2.utility.HRPMProperties.(HRPMProperties.java:78)
at g2.utility.HRPMProperties.getInstance(HRPMProperties.java:94)
at g2.gui.workers.ApplicationSwingWorker.(ApplicationSwingWorker.java:36)
at g2.main.Main.main(Main.java:37)

leggendo un file di proprietà Java in formato XML. Ho ricontrollato il classpath e le librerie erano tutte al loro posto, quindi mi è stato un po' difficile individuare il problema. Ho aggiornato Xerces, ho provato a copiarne diverse versioni ma niente. Infine qualcuno sul forum della Sun mi ha indicato la soluzione: Java 6 viene distribuito con la sua versione di Xerces, e quindi forzare l'utilizzo di una versione differente può creare alcuni problemi di compatibilità. Basta rimuovere allora i package di Xerces dal classpath per risolvere il problema.

giovedì 2 ottobre 2008

Communicating thru Intenet

It's amazing how easy communicating thru Internet is. Just as an example yesterday I got a contact from Rick McKinney, an archer myth for myself! This is just the last important and/or famous person I met thru Internet, and in fact in the past I got contact with a lot of important developers (from PostgreSQL to Samba and Linux....).
This is one of the things I like the most about Internet: it does not matter who you are or what you do, you can always and easily meet people you only heard about!

WhiteCat: injecting roles into Java agents/proxies

In the past few months I developed the prototype of a role system for Java agents that I called WhiteCat, in contrast to RoleX (also known as BlackCat).
The prototype is developed in 100% Java and is based, as its precedessor, on the Javassist bytecode manipulation library. The idea is the same as in RoleX: Java agents should be enhanced thru roles (i.e., Java third party libraries) dynamically at run-time, and must be merged with the role they assume, becoming a single entity with their roles. The aim is thus to support role external visibility, that is the capability to recognize a role played by an agent simply looking at it. Since in Java "looking" at an object and retrieving its class information, the WhiteCat approach must manipulate the agent class structure in order to make the role visible as a part of the agent itself.
For a more detailed explaination of the inspiration behind this role approach please see this article on the IBM Systems Journal.

There are a few drawbacks in the RoleX design that lead me to the design of the WhiteCat approach:
  • RoleX merges the role in the agent changing the whole agent class structure. This means that not only the bottom of the agent class inheritance chain is modified, but that each level of the agent inheritance is changed depending on the role class structure. This is a time consuming activity.
  • RoleX requires a different class loader for each role assumption/release. This means that if the same agent assumes different roles at different times, each assumption requires a different class loader (called role loader). This is resource consuming.
  • RoleX requires developers to deal with reflection and invocation translators to make injected features (i.e., role features) available. This is complex to understand and to develop/mantain.
  • RoleX provides only one kind of role, that is a publicly visible role. Each assumed role is automatically visible to external entities, and this could lead to security and privacy problems.
  • RoleX injects the role into the agent class, without taking into account that the agent could be hidden behind a proxy (see for example Aglets), and thus the role external visibility is not exploitable.
  • RoleX requires the role to be not instantiated and used by anything that is not the role loader. In other words you are not free to create a role object, since the role engine will workonly with the role classes, and thus having a role object will not provide you any meaningful capability.
  • RoleX creates different class definitions at run-time, so you could have two classes with the same name and different implementation. It can thus be difficult to deal with objects, since you could not knowor recognize which one is the original (i.e., never manipulated) one. Moreover, this way of working requires that developers discard the old (i.e., not manipulated) agent reference and use the new one provided by the role engine. Of course, there is no way to enforce this practice, so a malicious developer could keep a reference to both.

Starting from the above drawbacks I decide to design a new approach with the same base concepts, but faster, simpler and with more role visibility options. The result is the WhiteCat prototype that provides three level of role visibility:

  • invisible: the role is not visible at all from an external point of view. This means that an agent has assumed and uses a role without letting any other agent to be able to autonomously knowing it;
  • visible: the role is visible to any external entity;
  • public: the role is visible and can even be used from external entities.



Role visibility is defined thru interfaces and annotations, so that the role loader can recognize how and where to apply changes to the agent (or its proxy).

Moreover WhiteCat allows the manipulation of either the agent class structure or its proxy one. In the case the agent is hidden behind a proxy, and the role is visible or public, the proxy class structure is changed in order to make the role perceivable; in the case the role is directly accessible (i.e., there's no proxy) its class structure is directly changed in order to apply changes.



As an example consider the following application snippet:

 // role class
Class roleClass = root.loadClass("whitecat.example.DatabaseAdministrator");
DatabaseAdministrator dbaRole = (DatabaseAdministrator) roleClass.newInstance();
AgentProxy proxy = .... // get the proxy in the way your platform allows you

// get a new role loader engine
RoleEngine engine = new RoleEngine();
// add the dbarole to the current agent
AgentProxy newproxy = engine.injectPublicRole(proxy, dbaRole);

if( newproxy instanceof IDatabaseAdministrator ) {
// the proxy can work as a IDatabaseAdministrator object from here!
}




As you can see the agent proxy is simply injected with the role. Please note that a role instance is used, not a role class. This means that the role can be instantiated and initialized as you like, and can injected to the agent or its proxy when you want, and of course the role will keep its state.
Just after the injectPublicRole() call, the agent proxy is perceivable (thru instanceof) as implementing the public role interface, that in the above example is the IDatabaseAdministrator one. In order to achieve this, the agent proxy class structure is extended by the role one, meaning that it is like the agent proxy has new subclasses with the role properties. Since the agent proxy class structure is extended (i.e., all the classes up to the agent proxy are not touched), there's no need to discard the "old" object reference. If the developer does not use the new proxy reference (i.e., newproxy in the code above), it will simply not be able to exploit role capabilities, but he will be able to exploit all
original proxy capabilities.
The RoleEngine is a special class loader that performs bytecode manipulation in order to extend the agent proxy class chain. The RoleEngine exploits the Javassist library in order to manipulate the class structure, and appends
to each new class a unique number, so that the same class can be manipulated different times by the same RoleLoader as the result will have a different name and so will not clashes with other already manipulated classes. Moreover the role adoption model is simpler than in RoleX, since the developers will handle roles in straight way: once the injectPublicRole() is called, the developer could
test the agent proxy against the injected role and cast the agent proxy to such role. Last but not least, since WhiteCat does not manipulate a whole inheritance chain, rather it appends a chain to another, the approach is much faster than the RoleX one.

Of course, as shown in the figure, the manipulation process can be repeated as many times as needed (i.e., one for every role assumption).




In my opinion WhiteCat represents a very enhanced role approach than RoleX, and even if still a prototype, it is enough stable to be used in role based applications.
I'm still working on WhiteCat, and I will release it under the GNU GPLv3 license. If you are interested in WhiteCat and want to know more details or discuss with me, please e-mail me (fluca1978 at gmail.com) and I will be happy to provide more information.
I'd like to thanks Mr. Shigeru Chiba and the JBoss team and community for their work and support on Javassist.