giovedì 30 aprile 2009

Inviare e-mail da PostgreSQL

Una delle caratteristiche che contraddistinguono maggiormente PostgreSQL da altre soluzioni database è la capacità di poter eseguire diversi linguaggi di programmazione per la scrittura di funzioni e trigger.
In sostanza PostgreSQL ospita un linguaggio ed esegue il codice espresso in quel linguaggio integrandolo con i dati e i valori passati da un ambiente SQL. Vagamente questo approccia ricorda la programmazione CGI, ove il motore server invoca un programma esterno e lo esegue. La differenza è che nel caso di PostgreSQL il linguaggio viene eseguito in modo perfettamente integrato nel database.

PostgreSQL riconosce due tipi di linguaggi ospite: trusted e untrusted. I primi vengono eseguiti in un ambiente fortemente controllato, e di conseguenza possono eseguire poche operazioni. I linguaggi untrusted invece possono fare tutto quello che è concesso al loro linguaggio (caricare moduli, librerie, ecc.), ma come conseguenza devono essere gestiti da un superutente del database. PostgreSQL quindi permette ad un utente di usare un linguaggio untrusted, a patto che sia proprio l'amministratore del cluster a "confermare" che si è a conoscenza dei rischi che si stanno correndo.

Grazie all'uso dei linguaggi untrusted è possibile usare linguaggi che carichino moduli che ci semplificano diversi compiti, e nel mio caso l'invio di e-mail da una stored procedure.
Per questo ho scelto di usare Perl untrusted (plperlu), che si installa nel database con:

createlang plperlu

Successivamente si puo' creare una stored procedure per l'invio delle e-mail. Siccome in un caso reale si vorra' inviare una e-mail in base a dei dati presenti nel database, il seguente esempio mostra come effettuare una query con le funzioni spi e costruirsi il corpo della e-mail con questi valori. Da notare come la funzioni accetti tre parametri SQL che vengono usati da plperl come normali parametri Perl di una funzione.

CREATE OR REPLACE FUNCTION notifica_email( integer, integer, text )
RETURNS integer AS
$BODY$

use Mail::Sendmail;
use MIME::Base64;
use MIME::QuotedPrint;

my ($id, $limit, $categoria) = @_;


# query per estrarre informazioni dalla tabella
$sql = " SELECT codice, id_elemento, categoria, email FROM myTable ";
$sql .= " WHERE id_elemento = $id AND categoria = '$categoria' ";
$sql .= " LIMIT $limit ";


# esecuzione della query per ottenere i risultati da processare
$resultSet = spi_exec_query( $sql );



# numero di righe restituite
$numRows = $resultSet->{processed};
elog(INFO, "Trovate $numRows righe");

$ret=0;

ciclo: for( $i = 0; $i <= $numRows; $i++ ){
$rigaCorrente = $resultSet->{rows}[$i];

elog(INFO, "\nIterazione numero $i di $numRows\n");

# codice dell'elemento corrente
$codice = $rigaCorrente->{"codice"};
# categoria di questo elemento
$categoria = $rigaCorrente->{"categoria"};
# id elemento
$id_elemento = $rigaCorrente->{"id_elemento"};
# email a cui inviare le e-mail
$email = $rigaCorrente->{"email"};
# altri campi qui....


# costruisco il messaggio del warning
$messaggio = "Messaggio e-mail da PostgreSQL: $id_elemento, $categoria";

# costruisco un soggetto per l'e-mail
$subject = "Email da PostgreSQL";
elog(INFO, "\n$subject");

# email di backup in copia all'amministratore
$administrator_backup_address = "myself@myself.net";


# costruzione della mail da inviare
%mail = ( From => "postgresql\@postgresql.org",
To => "$email",
Cc => "$administrator_backup_address",
Subject => "$subject",
);

# invio e-mail
sendmail( %mail ) or die( $Mail::Sendmail::error) ;
# incremento il numero di messaggi inviati fino ad ora
$ret++;


}



# restituisco il numero di messaggi inviati da questa procedura
return $ret;



$BODY$
LANGUAGE 'plperlu' VOLATILE
COST 100;
ALTER FUNCTION notifica_email() OWNER TO postgres;

E' possibile invocare la funzione con, ad esempio:

select * from notifica_email( 1, 2, 'prodotti' );

Da notare l'uso di elog() per la visualizzazione di messaggi in modo analogo all'uso di RAISE in una funzione plpgsql.

Qt: la gestione dei layout

I layout della libreria Qt, classi ereditare da QLayout, sono molto potenti e semplici da usare. I programmatori di Trolltech hanno fatto un così buon lavoro che dalla prima versione della libreria ad oggi esistono pochissimi layout (QGridLayout, QHBoxLayout, QVBoxLayout) capaci di svolgere tutte le funzioni che complessi layout manager svolgono in altri GUI-toolkit.
Tuttavia la gestione di un layout in Qt potrebbe portare a qualche dubbio circa dove gli oggetti sono collegati e a come funzionano. Consideriamo il seguente esempio:

QWidget* container = new QWidget();
QHBoxLayout* layout = new QHBoxLayout( container );
QPushButton* b1 = new QPushButton("Pulsante 1", container);
QPushButton* b2 = new QPushButton("Pulsante 2", container);
layout->addWidget( b1 );
layout->addWidget( b2 );
container->setLayout( layout );

Il fatto "anomalo" è che i pulsanti vengono creati avendo come parent il widget container, e poi vengono anche aggiunti al layout, che a sua volta è usato dal container per disporre i widget. Ma perché è necessario "aggiungere" i componenti sia al pannello contenitore che al layout? La ragione di cio' risiede nel modo in cui i layout funzionano.
Ogni layout mantiene al suo interno una struttura interna con riferimenti ai widget da visualizzare (es. una lista); quando il widget che ha impostato il layout necessita di una visualizzazione, il layout scorre la lista dei suoi widget e calcola la geometria di ognuno di essi (ad esempio la dimensione di un pulsante). Per ogni componente il layout invoca setGeometry() in modo da specificare come e dove visualizzare il widget. Invece la relazione di parentela fra i widget è necessaria per la gestione della memoria Qt. Ecco quindi che ogni widget deve essere aggiunto ad un genitore affinché si abbia la gestione della memoria, e ad un layout affinché quest'ultimo possa calcolarne le dimensioni.
Rapportando il codice di cui sopra a Java si nota come quest'ultimo risulta molto piu' compatto:

JPanel container = new JPanel();
FlowLayout layout = new FlowLayout();
container.setLayout( layout );
JButton b1 = new JButton("Pulsante 1");
JButton b2 = new JButton("Pulsante 2");
container.add( b1 );
container.add( b2 );

Quello che si nota è che i componenti vengono aggiunti solo al pannello container, che si fa carico poi di aggiungerli (o comunicare la loro presenza) al layout manager quando necessario. L'approccio Qt è invece inverso, si delega la gestione dei componenti al layout manager che li deve gestire esplicitamente. Inoltre è possibile avere casi in cui un componente non deve essere aggiunto al layout (magari perché non visibile) ma deve far parte comunque del widget (ad esempio per la gestione della memoria). Ad ogni modo l'approccio Qt è convertibile in quello Java adattando il codice di un Widget affinché passi la sua lista di Widget al layout nel momento in cui questo la debba conoscere. E' una scelta implementativa.

Da notare poi che nelle ultime versioni della libreria è anche possibile scrivere codice piu' compatto, come il seguente:

QWidget* container = new QWidget();
QHBoxLayout* layout = new QHBoxLayout( container );
QPushButton* b1 = new QPushButton("Pulsante 1");
QPushButton* b2 = new QPushButton("Pulsante 2");
layout->addWidget( b1 ); // internamente esegue b1->setParent( container );
layout->addWidget( b2 ); // internamente esegue b2->setParent( container );
container->setLayout( layout );

In questo caso i componenti sono aggiunti direttamente e solo al layout, che viene poi usato come layout manager di un widget principale. Si presti attenzione però al fatto che il layout manager fa solo da "passacarte" fra il widget principale e quelli secondari. Infatti ogni widget aggiunto al layout manager non appartiene al layout (ovvero non ha come parent il layout manager, poiché un widget può avere come parent solo un altro widget), bensì il layout manager imposta il parent di ogni widget al container che sta usando il layout.


Differenze con Java
L'approccio Java al layout è molto simile, ma la lista dei componenti non è nota a priori al layout, che riceve in ingresse al momento necessario il parent, ossia il componente contenitore (ad esempio un JPanel). Il layout richiede quindi al componente la lista di tutti i componenti e li posiziona geometricamente usando setBounds() su ogni componente.
La differenza fra i due approcci risulta quindi nella posizione in cui la lista dei componenti da sottoporre a layout viene gestita.

Qt: la gerarchia degli oggetti

La libreria Qt prevede che ogni oggetto abbia un parent, ossia un genitore responsabile della sua vita. Questa scelta è molto importante se si considera che Qt lavora in C++, dove la gestione della memoria è affidata al programmatore. Per ovviare alla proliferazione di oggetti "dimenticati" (e quindi memory leak), Qt adotta la scelta di organizzare gli oggetti a run-time in un albero, in modo che ogni oggetto sia sempre raggiungibile tramite un nodo padre (il parent appunto). Avendo un albero di oggetti è possibile quindi eliminare un intero sottoalbero agendo sul nodo padre, ed è proprio quello che avviene in Qt: ogni volta che viene eliminato un parent tutti i suoi figli sono eliminati. Questo significa che l'operazione di delete su un oggetto Qt implicherà una delete ricorsiva su tutti gli oggetti che hanno il primo come parent.
Per gli sviluppatori della TrollTech, questa scelta è così importante che ogni oggetto Qt prevede, nel costruttore, un riferimento ad un oggetto padre, che diventerà il responsabile della distruzione dell'oggetto stesso.
A prima vista questo puo' sembrare un po' vincolante nel codice, infatti supponendo di avere un pannello al quale si vogliono aggiungere tre pulsanti, il codice appare come:

QWidget* container = new QWidget();
QPushButton* b1 = new QPushButton("Pulsante 1", container);
QPushButton* b2 = new QPushButton("Pulsante 2", container);
QPushButton* b3 = new QPushButton("Pulsante 3", container);

Come si nota, ogni oggetto contenuto (QPushButton) deve specificare il proprio parent (in questo caso container). Si noti che è possibile costruire un oggetto senza specificare il nodo padre, ed è poi possibile specificarlo in un secondo momento con il metodo setParent(), ad ogni modo la scelta di includere il parent nel costruttore è una sottolineatura di come sia importante, nella gestione della memoria Qt, la costruzione dell'albero degli oggetti.

Confrontando questo approccio con quello Java, si potrebbe storcere il naso, poiché quest'ultimo risulta piu' intuitivo da leggere. Il codice corrispondente all'aggiunta dei tre pulsanti ad un pannello risulta infatti:

JPanel container = new JPanel();
JButton b1 = new JButton("Pulsante 1");
JButton b2 = new JButton("Pulsante 2");
JButton b3 = new JButton("Pulsante 3");
container.add( b1 );
container.add( b2 );
container.add( b3 );

o anche in modo equivalente:

JButton b1 = new JButton("Pulsante 1");
JButton b2 = new JButton("Pulsante 2");
JButton b3 = new JButton("Pulsante 3");
JPanel container = new JPanel();
container.add( b1 );
container.add( b2 );
container.add( b3 );

La differenza rispetto all'approccio Qt è che in Java è possibile costruire i singoli componenti e aggiungerli semplicemente al contenitore in un secondo momento, mentre in Qt è necessario definire prima il contenitore e poi specificare, per ogni componente, dove questo deve essere contenuto. Se è vero che anche in Qt si sarebbe potuto scrivere:



QPushButton* b1 = new QPushButton("Pulsante 1");
QPushButton* b2 = new QPushButton("Pulsante 2");
QPushButton* b3 = new QPushButton("Pulsante 3");
QWidget* container = new QWidget();
b1->setParent( container );
b2->setParent( container );
b3->setParent( container );

è pur vero che questa tecnica è scarsamente usata e incoraggiata. La ragione risiede proprio in cio' che è stato detto prima: Qt forza la definizione della relazione fra gli oggetti fin dalla loro costruzione, al fine di impostare correttamente da subito la gestione futura della memoria.
Per meglio comprendere l'importanza di cio', si consideri il seguente esempio Java e il corrispettivo Qt (in stile Java):

JButton b1 = new JButton("Pulsante 1");
JButton b2 = new JButton("Pulsante 2");
JButton b3 = new JButton("Pulsante 3");
JPanel container = new JPanel();
container.add( b1 );
container.add( b2 );

e in Qt stile Java:

QPushButton* b1 = new QPushButton("Pulsante 1");
QPushButton* b2 = new QPushButton("Pulsante 2");
QPushButton* b3 = new QPushButton("Pulsante 3");
QWidget* container = new QWidget();
b1->setParent( container );
b2->setParent( container );

rispetto agli esempi di prima, qui vengono creati tre pulsanti, ma solo due sono effettivamente aggiunti al container, mentre il terzo viene "dimenticato". Ma se in Java scatta il garbage collector a recuperare la memoria del terzo pulsante, in C++ nulla del genere avviene, e siccome il terzo pulsante non ha nessun padre, non viene eliminato automaticamente mai, nemmeno quando il container cessa la sua vita. Ne consegue che così facendo si rischia di avere dei memory leak. Ecco quindi che Qt ovvia al problema imponendo, a tempo di costruzione degli oggetti, di specificare esattamente le relazioni che intercorrono fra di essi. Solo così l'albero degli oggetti puo' essere creato e mantenuto.

Si noti poi che ogni Widget prevede, come valore di default, un puntatore nullo ad un parent widget. Come conseguenza, un widget puo' sempre essere costruito senza parent, anche se questo richiede maggiore attanzione al programmatore per la gestione della memoria.

Da ultimo, Qt mette a disposizione una classe particolare QPointer, che agisce come un puntatore tipizzato ad un QObject. La differenza fra un QPointer e un puntatore normale è che il primo reagisce (tramite uno slot) quando il componente al quale punta viene cancellato. Infatti il QPointer viene azzerato (impostato a null), in modo da indicare che non punta piu' a nessun oggetto. Lo scopo è quello di consentire ad un programmatore di mantenere puntatori sicuri a oggetti nella gerarchia degli oggetti Qt, in modo che se un oggetto viene cancellato (poiché lo è il suo parent), il puntatore venga immediatamente invalidato.

domenica 26 aprile 2009

Mapping PASSI to Rolex...authors were lost!

WARNING: I believe that a scientific contribution should always be discussed.
This could not be the right place to discuss it, but it could be a starting point.
The following blog entry discusses a paper on a system I designed and developed that is, in my opinion, wrongly adapted to provide a scientific contribution I don't agree with.
Please remind that all opinions expressed here are on my own.


As the main designer and developer of RoleX (aka BlackCat), a Java framework for dynamic role injection thru run-time bytecode manipulation, I cannot express positively about the paper "Mapping PASSI and RoleX". Such article in fact presents a description of RoleX that is almost wrong, and therefore I don't believe that the conclusions this paper presents are scientifically valid.
Such paper, written within the MENSA project (a multi-university project)
should have been written with a stricter description of RoleX and of the design/aim of the latter.
Having read a work in progress draft in the beginning of 2008, before the final paper was published, I claimed about several errors in the RoleX description, but I see authors did not fix the paper. If authors asked me for an explaination of those concepts of RoleX that are still not clear to them, I surely provided all the required details.
It seems to me that the paper is trying mapping apples to oranges, nevertheless it has been succesfully published to the 2nd International Symposium Agent Based Modeling and Simulation, the 19th European Meeting on Cybernetics and Systems Research (EMCSR 2008), and this also means not all the paper is wrong. Let's say it is a nebolous paper to me.
Interested readers should read [1] before continuing, in order to acquire needed RoleX background.

General Discussion
The paper proposes an interesting aim: mapping the RoleX implementation to the PASSI methodology. This is surely interesting and challenging, but it must stand out on a clear RoleX background and experience, as well as a PASSI knowledge able to cover lacks in the former or the latter and how to overtake migration and integration issues.

The Rolex Meta-Model
The RoleX meta model described on section 2.2 has several errors, most of them clearly visible in Figure 2. First of all, from Figure 2 it is possible to note how a RoleDescriptor is composed by one or more ActionDescriptor and one or more EventDescriptor. This is not correct, since as it is possible to see from [1], Figure 5, where it is clearly shown how descriptor are nested. Authors seems to have reported a distorted version of [1], Figure 6, where it is shown how an EventDescriptor can be embedded directly into a RoleDescriptor, even if no ActionDescriptor is provided for it. Nevertheless, the important thing is that the descriptor are usually nested (RoleDescriptor contains ActionDescriptor that contains EventDescriptor), with the exception that a RoleDescription can directly contain one or more EventDescriptor. Instead from the Figure 2 only such exception is possible.

Another interesting mistake is about the association between a Role and its descriptors. From Figure 2, it appears that a Role has a RoleDescriptor, and that is true, but it is not as depicted in Figure 2. First of all, a Role and a RoleDescriptor are not tied in any way. The agent works always using RoleDescriptors and never using Roles, and this is visible in code snippet of [1], Figure 17, where the agent searches for and assumes a role only thru its descriptor. The adoption of descriptors is better explained in [2]:

The descriptors are useful also for hiding to the agent the physical
location of the role implementation, allowing agent programmers
to disregard about the work of role programmers, and viceversa,
because the role behavior is described in a separate way.
Here the key is role implementation hiding: in order to allow an agent to use the role only thru the injection mechanism, RoleX does not allow an agent to get (and instantiate) a role implementation directly. In other words, the Role Repository keeps the role implementation hidden, exposing only the RoleDescriptors, that are not tied to the role implementation in any way. In fact, it is the Role Repository that knows each descriptor to which role is tied and not, as suggested in Figure 2, a role that knows its descriptor. More details on the adoption of descriptors and role repository can be found in [3] and [4].

A close look to Figure 2 emphasizes another embarassing detail: a role class has a navigable link to a role descriptor, and that is not true. Roles and descriptor are developed separately and are kept separate untill they are installed in the system. Installing a role in the system means that the role repository keeps information about a role and its descriptor. This also means that the role repository is the only component that, at run-time, contains a binding between a role and its descriptor. Thanks to that, it is possible to install the same role several time with different descriptors, or even to substitute a role behind a descriptor, and so on.

Now, having a look at older papers about RoleX, it is clear that a class diagram such as that of GFigure 2 has never been depicted. The reason is simple: RoleX is a dynamic framework, and being dynamic means that a lot of bindings are resolved only at run-time and through connection components (e.g., the role repository above). Therefore, it does not make any sense at all showing a static class diagram to glance at a dynamic system.

But section 2.2 lies on the RoleX role definition itself, and in fact it states that:

In RoleX, a role is defined as a set of actions that an agent playing such role can perform to achieve its task, and a set of events that an agent is expected to manage in order to “behave” as requested by the role it plays.
That's not true, since the action-event definition is specified in the BRAIN framework and not in RoleX! In fact, in [5] section 2.1 there is the declaration of the BRAIN role model:

In BRAIN, a role is defined as a set of capabilities and an expected behavior. The former is a set of actions that an agent playing such role can perform to achieve its task. The latter is a set of events that an agent is expected to manage in order to “behave” as requested by the role it plays.

As stated later in [5], RoleX is just one of the available implementation of BRAIN, and thus it is compliant to such role model. Not only the authors confuse BRAIN and RoleX, but they ignore the RoleX role definition, that being compatible with the BRAIN one, is expressed in [1] as:

Defining a role as a few classes and interfaces

It's now time to see how the authors describe the invocation translator:

The use of descriptors means that the programmer cannot write code that invokes methods corresponding to role actions in the usual way, because a compile-time error will occur. Therefore, there must be an invocation translator that do introspection on the extended agent to dynamically find which method must be called in response to an invocation on an action description.

The above seems a raw cut-and-paste of different articles and concepts. The fact is this (see [1], Figure 4 and description on page 190): when RoleX performs bytecode manipulation, it injects into an agent new members (the role members). It is clear that the agent has now new methods and properties, that before the role injection it didn't have. For this reason, the programmer cannot invoke directly the new methods because they are not present at compile time and because it does not know them directly (the role implementation is hidden). For this reason, the agent have to perform introspection to get knowledge of the new members and to use them. It is only to simplify such introspection process, and to complete the adoption of descriptors, that the invocation translator exists, and in fact it allows to:
  1. access an added member without having to adopt introspection;
  2. execute an action starting from its descriptor, and thus without the needing to know which action to execute.
It is thus clear that (i) the presence of an invocation translator is not a must (an agent can perform introspection by its own) and (ii) the invocation translator is not a consequence of the adoption of role descriptor, but rather a feature that helps programmer using descriptors.



Mapping PASSI to RoleX
Section 3 of the article shows the concrete mapping between PASSI and RoleX. Having provided readers with an almost totally wrong definition of RoleX, the mapping cannot not be correct, and in fact there are several mistakes. Let's start from Table 1, where PASSI concepts are mapped 1:1 to RoleX ones. First of all, it is worth noting how RoleX does not have a concrete action, but only a concrete action descriptor. As described before, the action concept derives from BRAIN, while RoleX implements it only by means of action descriptors. It is therefore incorrect to map the PASSI agent action to a RoleX action, while it is correct to map the former to a RoleX action descriptor (as the authors partially do).

Authors identify a PASSI service with the event handling mechanism of BRAIN/RoleX, and this is not fully correct. In fact, even if it is true that an incoming event can represent a service request, RoleX injects into agents role members, that can be accessed (if publicly available) from other agents. In other words, a role service could be also an OOP-method injected into an agent, therefore a PASSI service should be mapped both on event handling and role methods (or better action descriptors).

Finally, it is almost wrong the mapping between a PASSI goal and a RoleX role descriptor. First of all, a role (and its descriptor) is not a goal in RoleX, rather an enabler to achieve one or more goals. It is clear that a role cannot be a goal in RoleX also for the external visibility: a role has a set of static properties, such as its exeternal visibility that allows another agent to know which role an agent is playing simply "watching" at it. How can it be expressed as a goal? A goal is something that an agent should actively achieve, and thus it can be specified by actions, as stated in [5]:

In BRAIN, a role is defined as a set of capabilities and an expected behavior. The former is a set of actions that an agent playing such role can perform to achieve its task.

It is therefore clear that a role, in RoleX, is not a goal, rather a goal container, since it contains actions that can be used to achieve goals. Moreover, to achieve a goal, the actions could be serialized into one or more sequences, that is not imposed in any way in RoleX. This, again, specifies how a RoleX role cannot be a goal. It is interesting to note that the authors themselves recognize this, in contrast to Table 1, stating that:

One of the major drawbacks of RoleX is that it fails in defining goals (or tasks in PASSI terminology). Actually, the goal is distributed in the role descriptors, but there is not a way to directly define it.
This sentence must be analyzed very well. First of all, it is not RoleX's fault if the definition of goal is scattered within a role descriptor, since this is the definition that comes from BRAIN. It is worth noting, at this point, that while BRAIN does not include a definition of goal anywhere, RoleX does. In fact, as shown in [6] Figure 5, each kind of descriptors include an aim specification, that can be used to specify the goal of the element. In particular, applying the aim to action descriptors, we can express the goal of each action.

It's now time to examine the context element, that even if virtually available in RoleX, does not find any concrete implementation, and in fact is not either specified in the XRole schema definition (see [6]). So, the mapping between the PASSI scenario and the RoleX context cannot be possible, being the latter not present at all. This should be listed in the last paragraph of section 3, that explains which concept do not have a 1:1 mapping.

With regard to such last paragraph, it is interesting noting that the role repository should not be listed there. In fact, each role approach could have a way to list and provide roles to agents, and the role repository is, after all, doing that. So, while it is true that the adoption of the repository is an implementation issue, it is also true that PASSI is lacking modeling it and that a lot of other role approaches have their kind of role library.



What is the key point authors missed?
In my opinion, this article is wrong even in the title. Authors are trying to map a methodology (PASSI) over an implementation (RoleX), and there's nothing wrong with that. But they discard that RoleX is compatible with another methodology, that is BRAIN. So, before showing how PASSI could be mapped on RoleX, they should demonstrate that PASSI and BRAIN can coexist and can be mapped each other, or at least that RoleX has so many implementation details that go out of bounds of BRAIN and that can be used in PASSI.
Having that, it is possible to demonstrate and convince readers about the PASSI to RoleX mapping.


REFERENCES

1 CABRI, FERRARI, AND LEONARDI, Injecting roles in Java agents through runtime bytecode manipulation, IBM SYSTEMS JOURNAL, VOL 44, NO 1, 2005

2
Cabri, Ferrari, Leonardi, Enabling Mobile Agents to Dynamically Assume Roles, The 2003 ACM International Symposium on Applied Computing (SAC), Melbourne, Florida, USA, March 2003


4 Luca Ferrari, PhD thesis (February 2006)

5 Cabri, Ferrari, Leonardi, Supporting the Development of Multi-Agent Interactions via Roles, The International Workshop on AGENT-ORIENTED SOFTWARE ENGINEERING (AOSE-2005)

6 Cabri, Ferrari, Leonardi, Exploiting Run-Time Bytecode Manipulation to Add Roles to Java Agents, Science of Computer Programming, (Elsevier, Amsterdam-NL), Vol. 54, No. 1, pp. 73-98, January 2005 ISSN: 0167-6423

giovedì 23 aprile 2009

Diversi modi di correlare i dati in un contenitore

Con questo articolo voglio prendere in considerazione, da un punto di vista didattico, i diversi modi messi a disposizione da Java per correlare fra di loro i dati di una collezione.

Si consideri il caso di una serie di articoli da inserire in appositi scaffali. La programmazione OOP ci insegna che Articolo e Scaffale devono essere modellati come classi poiché sono astrazioni di dato. Ma come mettiamo in relazione le istanze delle due classi? Ovvero, come implementiamo il legame secondo il quale uno scaffale contiene uno o piu' articoli? Il problema puo' essere risolto banalmente con una Collection, ad esempio una lista, contenuta in Scaffale e che a sua volta contiene degli elementi Articolo:

public class Scaffale{
...
List<Articolo> articoli = ...
...
}

Nessun problema fino a quando la relazione scaffale-articolo non deve essere arricchità di nuove informazioni. Consideriamo ad esempio che si debba anche memorizzare la quantità di ogni articolo memorizzato in uno scaffale. Diverse soluzioni sono possibili al problema, e nel seguito le tratto una ad una con pregi e diffetti.

Implementazione delle informazioni aggiuntive nell'oggetto contenuto (Articolo)
Questa soluzione richiede, ad esempio, che la classe Articolo contenga al suo interno un campo quantita' che esprima il numero di pezzi di un articolo una volta che questo viene riposto in uno scaffale.
Ovviamente questa soluzione è difettosa dal punto di vista OOP: si stanno inserendo informazioni relative ad una associazione nell'elemento associato, e quest'ultimo sarà dotato di tali informazioni anche quando non associato a nessun scaffale (es. in anagrafica articoli). Inoltre, all'aumentare del numero di informazioni relative all'associazione, si ha un aumento progressivo della complessità della classe contenuta (Articolo). Questo aumento di complessità non solo rende il codice piu' complesso da manutenere, ma vincola la libreria che si sta realizzando: infatti la classe contenuta dovrà essere dotata di opportuni metodi pubblici di accesso alle informazioni di associazione (es. getQuantita() ), ma un metodo pubblico vincola la libreria e rende estremamente complesso il refactoring (non si puo' ridurre quello che è pubblico poiché non si sa a priori chi usa/userà tali metodi).

Ne consegue che questa soluzione è pessima e dovrebbe essere usata solo per esempi e programmi di estrema semplicità.


Creare una sottoclasse della classe contenuta (Articolo) e inserire nella sottoclasse le informazioni aggiuntive
Questa soluzione è una variante di quella precedente. In sostanza si crea una sottoclasse di quella contenuta (Articolo) in modo da estendere tale classe con le informazioni aggiuntive relative all'associazione. Tale sottoclasse verrà poi usata e contenuta all'interno del contenitore stesso (Scaffale), implementando di fatto una associazione che comprende sia le informazioni di base (Articolo) che quelle di associazione. Di fatto quindi si crea la sottoclasse e si specializza la classe contenitrice affinché contenga la nuova sottoclasse:

public class ArticoloEsteso extends Articolo{
private int quantita = 0;
....
}

public class Scaffale{
...
List<ArticoloEsteso> articoli;
...
}

Lo svantaggio di questa soluzione è quella di vincolare comunque le informazioni di associazione ad uno specifico articolo, ovvero ad uno specifico oggetto contenuto. Di fatto quindi è come se l'associazione si fosse spostata di livello, anziché dal contenitore ad un oggetto contenuto, da un contenitore ad un oggetto contenuto e potenziato. Inoltre questa soluzione, usando l'ereditarietà, vincola fortemente la classe estesa (come è naturale in una gerarchia).

Questa soluzione è generalmente accettabile, anche se spesso l'introduzione di un vincolo di ereditarietà impone limitazioni troppo forti per una buona manutenzione del codice.

Usare una doppia Collection nella classe contenitore (Scaffale)
L'associazione fra contenitore e contenuto viene realizzato tramite una collection, nei casi precedenti una lista di articoli contenuta in ogni istanza di scaffale. Siccome una collection può contenere un solo tipo di oggetto (tralasciamo casi in cui si memorizzano oggetti diversi poiché rappresentano casi di cattiva programmazione), può avere senso utilizzare due collection parallele: una che memorizzi l'oggetto contenuto (Articolo) e una che memorizzi le informazioni aggiuntive (ad esempio incapsulandole in un oggetto InformazioniStoccaggio). Finché le due collection saranno mantenute coerenti (ad es. l'articolo i-esimo è associato alle informazioni i-esime) non vi saranno problemi di sorta.
Chiaramente all'aumentare del numero di informazioni da memorizzare per associazione è possibile (i) modificare l'oggetto di informazioni affinché le contenga tutte oppure (ii) aggiungere una nuova lista che contenga le nuove informazioni. Ne consegue che questa soluzione è per molti versi flessibile e adattabile. Purtroppo però la gestione di due o piu' collection parallele può procurare diversi grattacapi, che possono poi sfociare in forti mal di testa quando gli indici di correlazione non corrispondano piu'.
Questa soluzione è pertanto implementabile quando si abbia un buon controllo sui meccanismi di correlazione delle collection e quando comunque queste non aumentino esageratamente (>3) in numero. Si noti infine che è opportuno implementare la politica di correlazione in modo che non sia modificabile da estensioni future, altrimenti si rischia di ricadere in problemi di correlazione difficili da individuare.

Usare una Map nella classe contenitor (Scaffale)
Questa soluzione è molto allettante, e di fatto rappresenta una naturale evoluzione della precedente. L'idea è quella di usare una Map, che altro non è che una Collection che mette in correlazione due oggetti fra loro. E' quindi possibile inserire nella mappa gli oggetti da contenere (Articolo) come chiavi, e come valori correlati oggetti di informazione:

public class Scaffale{
...
private Map
<Articolo, InformazioniStoccaggio> articoli;
...
}

Così facendo, è possibile dato un articolo ottenere in modo piuttosto semplice le informazioni correlate, come pure è possibile scorrere la mappa per avere l'elenco di ogni articolo. Di fatto, la Map realizza una doppia Collection sempre coerente.
Fino ad ora questa è la soluzione migliore, anche se presenta alcuni pericolosi trabocchetti:
  1. non deve mai essere ritornata, in nessuna eventualità, la mappa completa, bensì solo i suoi singoli elementi (Articolo e InformazioniStoccaggio). La penalità è di trovarsi nella impossibilità di fare un efficiente refactoring o di cambaire il comportamento di gestione della classe contenitrice;
  2. l'oggetto di informazioni correlate (InformazioniStoccaggio) non ha nessuna relazione autonoma con l'oggetto al quale si riferisce (Articolo), e di conseguenza dato un Articolo e un InformazioniStoccaggio non è possibile sapere se le informazioni sono correlate o provengono da sorgenti differenti. L'unica soluzione è quella di affidarsi allo Scaffale per avere le informazioni coerenti (si noti che questo problema si aveva anche nel caso di Collection correlate).
Tuttavia quelli appena esposti sono problemi generalmente piccoli, e che non pregiudicano il coding di una applicazione anche complessa, e quindi questa soluzione si presenta come una delle migliori.

Utilizzo di un Wrapper del contenuto (Articolo) e di una singola Collection nella classe contenitore (Scaffale) Questa soluzione è a mio avviso la piu' flessibile ed espandibile. L'idea è quella di usare una singola collezione, ad esempio una lista, nella classe contenitore (Scaffale), e di inserire al suo interno non direttamente l'oggetto contenuto (Articolo), bensì un wrapper di quest'ultimo che contenga anche delle informazioni supplementari. Ad esempio:

public class ArticoloInScaffale{
private Articolo articolo;
private InformazioniStoccaggio info;
...
}

public class Scaffale{
private List<ArticoloInScaffale> articoli;
....
}

In questo esempio ArticoloInScaffale ingloba Articolo, assieme alle informazioni correlate alla disposizione dell'articolo nello scaffale. E' abbastanza semplice dotare la classe Scaffale di opportuni metodi per estrarre gli articoli o le informazioni, e non si deve lavorare con collection a doppia dimensione, bensì con collection lineari. Inoltre questa soluzione è molto vantaggiosa per il code refactoring, poiché risulta molto semplice aggiungere informazioni complementari senza dover modificare il sistema di contenimento .

Conclusioni
Il metodo a mio avviso piu' portabile e manutenibile consiste nella creazione di un wrapper che colleghi ogni oggetto contenuto (Articolo) con le proprie informazioni, e l'uso di una singola collection rende molto piu' semplice da gestire la classe contenitore (Scaffale). Tuttavia questa soluzione richiede la scrittura di codice in piu', secondo la tradizione OOP dove le astrazioni regalo potenza, ma hanno un costo di setup iniziale.
Se si deve quindi realizzare una correlazione in poco tempo si utilizzi una mappa, altrimenti si usi un wrapper. Le altre soluzione sono a mio avviso da scartare per i sopracitati problemi.

mercoledì 8 aprile 2009

Eclipse: impostare un editor per un tipo di file

A volte eclipse non riconosce un determinato tipo di file e quindi si limita ad aprirlo con l'editor di testo base. E' questo il caso, ad esempio, dei file JNLP (Java Network Launching Protocol), che sono normali file xml. E' quindi necessario impostare Eclipse perché riconosca quale editor usare a seconda dell'estensione del file. Il processo è a due fasi:


  1. occorre aggiungere il tipo di contenuto nelle preferenze generali del workspace, specificando che il tipo di file sarà xml.
  2. occorre associare l'editor xml all'estensione del file specificata

A questo punto ogni volta che si tenterà di aprire il file verrà usato l'editor selezionato per quel tipo di contenuto.

martedì 7 aprile 2009

Riguardo alla previsione dei terremoti

Il terremoto dell'Abruzzo è una di quelle cose che non vorremmo mai vedere.
Ci terrorizza il solo pensare che potrebbe capitare anche a noi.
E in questi momenti, in cui serve solo rimboccarsi le maniche, trovano spazio anche le polemiche, come se lo scaricare la colpa su qualcuno (o qualcosa) possa farci sentire piu' tranquilli, quasi fosse la garanzia che "cose del genere non si ripeteranno piu'".

Non sono un esperto di terremoti. Anzi, non ne so nulla circa la loro trattazione. Però so come gira il mondo scientifico.

Ieri sera guardavo stupefatto le notizie alla tv, osservavo angosciato la situazione di queste persone sfollate, distrutte materialmente e spiritualmente. E fra le varie notizie torna a fare capolino il caso di Gioacchino Giuliani, un ricercatore (anche se lui si definisce tecnico) capace di prevedere i terremoti.

Lungi da me voler innescare altra polemica, ma qualche piccola considerazione è doverosa:
  • Giuliani è in grado di prevedere i terremoti, ma la sua famiglia è fra quelle sfollate. Mi sembra _stupido_ essere capaci di prevedere una catastrofe e lasciare la propria famiglia in balia degli eventi. Forse Giuliani non era in grado di prevedere la portata del terremoto, ma questo significa che il suo metodo non è affidabile e preciso.
  • Giuliani afferma che sono 10 anni che il suo metodo produce risultati accurati. Dieci anni sono lo spazio di una generazione. Trovo strano che il suo metodo non sia applicato in paesi all'avanguardia (America e Giappone). Forse Giuliani è sulla buona strada ma il suo metodo non è accurato.
  • Giuliani afferma che il suo metodo non viene applicato per colpa di una classe politico-dirigenziale a lui avversa. Quindi Giuliani smentisce la famosa "fuga dei cervelli", visto che anziché andare a brevettare all'estero il suo sistema rimane in italia a gridare "al lupo, al lupo!" senza essere ascoltato.
  • Da una _rapida_ ricerca non si trova nessuna pubblicazione di Gioacchino Giuliani. Gli esperimenti e i risultati di Giuliani a che comunità scientifica sono stati sottoposti?
Non e' veramente il momento di fare polemica, ci sono altri problemi da risolvere prima. Ma sono sicuro che i media faranno a gara per strappare qualche punto su questa faccenda. Spero che vengano anche mostrati dati scientifici certi circa i risultati di Giuliani.

E comunque in bocca al lupo a tutti!

venerdì 3 aprile 2009

JiT vs Optimizer

Mi capita spesso di sentir parlare di compilatori JIT (Just In Time) e Optimizer (ottimizzatori) e mi accorgo che spesso i due sono trattati allo stesso modo, seppur siano differenti. La differenza maggiormente evidente è che un JIT compiler compila il corpo di un metodo in codice nativo al primo accesso al metodo stesso, mentre un optimizer (ri)compila il metodo in codice nativo quando lo ritiente opportuno (ovvero quando si può verificare una vera e propria ottimizzazione).
Per comprendere meglio, si consideri il generico metodo foo() che viene richiamato dall'applicazione. Il JIT compiler compilerà foo() in codice nativo al suo primo accesso, mentre un optimizer lo ricompilerà solo quando il numero di accessi al metodo sarà tale da far migliorare le prestazioni. In altre parole, l'optimizer analizza il codice in esecuzione e decide se, in base al numero di chiamate di foo() questo sia un metodo molto utilizzato (metodo hot) e quindi possa necessitare di ottimizzazioni (in particolare una ricompilazione in codice macchina) per le successive (si pensa frequenti) invocazioni.
Chiaramente entrambi i compilatori possono generare differenti ottimizzazioni, quali rimozione di codice inusato (dead code), srotolamento dei cicli, copy propagation, ecc. Ma la differenza sostanziale fra i due tipi di compilatori è nella decisione che viene presa circa la compilazione di un metodo in codice nativo.
Chiaramente si nota poi come un compilatore optimizer debba avere anche un supporto adattativo, ossia debba essere in grado di comprendere quando è ora di compilare un metodo. Per fare questo, occorre un qualche meccanismo di memorizzazione delle statistiche run-time di un sistema JVM.

mercoledì 1 aprile 2009

All'inizio....

Tutto è iniziato più o meno così, circa 19 anni fa....

Let it crash! (ovvero non tutto quello che è Exception deve essere gestito da TE!)

Una delle cose che mi piace di più del linguaggio Java è la severità del suo compilatore, resa particolarmente evidente nel caso delle eccezioni. Purtroppo il meccanismo delle eccezioni spesso non viene capito dai programmatori, che si affannano a costruire dei complessi blocchi try..catch per catturare ogni possibile errore che il proprio codice potrebbe sollevare.
Ma questo è sempre corretto?
In un'applicazione multi-threading spesso no. Generalmente le applicazioni multithread hanno uno schema gerarchico, con un thread padre che genera i figli per gestire diverse richieste (si pensi al classico server in attesa di connessioni). In uno schema del genere, il processo padre dovrebbe svolgere anche il ruolo di coordinatore e supervisore fra i figli, che si trovano a fare il lavoro sporco. Cosa succede se un'eccezione viene generate in un figlio? La maggior parte dei programmatori tenta di catturare l'eccezione, di gestirla e di ripristinare lo stato del thread (figlio). Ma l'eccezione viene generata nel thread figlio stesso, quindi il thread tenta di auto-gestire l'eccezione.
La domanda a questo punto è: il thread figlio è in grado di gestirla? Sa quale sia la decisione migliore? Generalmente no!
E' compito del processo coordinatore decidere cosa fare nel caso in cui un figlio termini la sua esecuzione in modo abnorme. Quindi è meglio implementare una logica decisionale nel thread coordinatore piuttosto che nei thread di lavoro. I thread di lavoro dovrebbero essere programmati in stile happy-case, ovvero considerando che tutto vada bene. E se qualcosa andrà male, sarà il coordinatore a decidere cosa fare.
Questa rinuncia di autonomia nei thread da lavoro potrebbe incrementare decisamente le prestazioni dell'intera applicazione. Infatti, un thread figlio difficilmente ha la visione complessiva dell'applicazione (stato della memoria, occupazione processore, stato dei pool,...) e quindi non può decidere cosa è meglio per l'applicazione (continuare o morire). Tanto vale allora lasciar(si) terminare e segnalare al chiamante (il processo coordinatore) che qualche cosa è andata storta; sarà lui a prendere la decisione opportuna (ricreare il thread, riconfigurare il pool, ecc.).

La pericolosità dei metodi void

Generalmente non ci si pensa mai, ma un metodo void (inteso sia come tipo di ritorno che come lista di parametri) è di fatto più difficile da controllare che un metodo con una lista di parametri e un tipo di ritorno.
Per comprendere meglio, si consideri un metodo con il seguente prototipo:

public int somma(int op1, int op2);

ora, il metodo accetta in ingresso due operandi (op1, op2) e li trasforma (li somma) per fornire un risultato in uscita. In sostanza il metodo opera come una funzione applicata al dominio degli operandi op1, op2 e produce un risultato nel codominio. Supponiamo che la funzione abbia una implementazione come segue:

public int somma(int op1, int op2){
this.somma = op1 + op2;
return this.somma;
}

e si supponga che il prototipo del metodo cambi in modo da non ritornare il risultato dell'applicazione della funzione:

public void somma(int op1, int op2);

Chiaramente il metodo compie ancora il suo scopo (salvare in una variabile interna ad un oggetto la somma), ma ciò potrebbe non essere chiaro al chiamante per via dell'incapsulamento. Si ha quindi un side-effect: il programma cambia il suo stato senza che ciò sia direttamente visibile.
Perché questo è problematico? Perché senza un debugger, senza introspezione, oppure senza una dichiarazione volontaria da parte dell'oggetto circa la sua mutazione di stato, quest'ultima risulterà invisibile al mondo esterno, e quindi difficile da comprendere. Ci si trova quindi in una condizione in cui è difficile, dal lato del chiamante, verificare se il metodo abbia realmente applicato la funzione, e dove sia stato memorizzato il risultato. Se da un lato questo è alla base dell'incapsulamento (i dati mascherati dalle operazioni), dal lato pratico rende più complesso analizzare e controllare il codice, e ciò potrebbe causare problemi in sistemi mission-critical.
Si supponga ad esempio che la funzione, a seguito di un cattivo aggiornamento, abbia la seguente implementazione:

public void somma(int op1, int op2){
this.somma += op1 + op2;
}

ovvero la variabile interna somma non memorizza più una reale somma ma l'accumulazione degli operandi. Come potrebbe un chiamante accorgersene? Se l'incapsulamento è buono, semplicemente non può accorgersene!

E' per questo anche che esistono le unit-test, e che appunto in casi come quelli qui sopra i test vengono svolti da classi nello stesso package o che comunque hanno accesso anche allo stato inerno. Ma le unit-test sono solo controlli, non risolvono il problema alla radice. Il problema in questo caso è che i mutators dovrebbero sempre fornire al chiamante un risultato che rispecchi la mutazione di stato. Non sempre è possibile, non sempre è conveniente, non sempre è comodo. Ma quando possibile, ritornare il valore dell'applicazione di un metodo consente di scrivere codice adatto a situazioni mission-critical. Non solo: i metodi che ritornano dei risultati permettono anche di fare un chain degli stessi, con il risultato di codice più elegante e compatto (si pensi alle API NIO).

Come sempre è necessario trovare il giusto bilanciamento fra ottimizzazione del codice e sicurezza dello stesso.

Gigetto viaggia nel tempo...

Domenica scorsa c'è stato il cambio d'orario, con le lancette che si sono spostate avanti di un'ora. Ebbene, in stazione a Formigine non sembrano essersene accorti, tanto è vero che il monitor con i treni in arrivo segnala il transito degli stessi un'ora indietro rispetto a ciò che è in realtà!