AspectJ: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
FrescoBot (discussione | contributi)
m Bot: piccoli errori di battitura
Riga 6:
===Join point e pointcut===
 
Un concetto basilare di '''AspectJ''' è quello di join point. Un join point può essere intuitivamente definito come un certo istante nell' esecuzione del programma; ogni chiamata a un qualsiasi metodo di un oggetto qualunque potrebbe essere un join point, così come leggere il valore di una variabile , creare un oggetto o modificare il valore di una variabile.
 
I pointcut invece descrivono le situazioni particolari che si vengono a creare durante l' esecuzione del programma. Un pointcut è cioè una sorta di [[variabile booleana]] il cui valore dipende da una certo insieme di join point, che in un dato momento dell' esecuzione del programma possono essere ''veri'' o ''falsi''.
 
È possibile definire un pointcut in maniera estremamente dettagliata; si può ad esempio definire un pointcut che sia valido quando un qualsiasi metodo della [[Classe (informatica)|classe]] A viene chiamato, o ancora, definire un pointcut che è valido quando un metodo di un oggetto di classe A chiama il [[metodo]] xyz(int a , int b) di un oggetto di classe B, oppure un pointcut che sia valido quando viene eseguito il metodo B.exec(String s) tranne nel caso in cui il suddetto metodo venga chiamato da un membro della classe F. È anche possibile definire un pointcut che sia valido quando uno qualunque di un certo insieme di metodi specificato dal programmatore viene chiamato.
 
Un pointcut può contenere informazioni sui join point che lo compongono, quali ad esempio gli argomenti del metodo chiamato (se il pointcut contiene un join point definito dalla chiamata di un metodo) o lo specifico oggetto cui era diretta la chiamata (sempre che il pointcut contenga un join point consistente nella chiamata di un metodo di un oggetto). Facendo riferimento alla metafora precedente, i pointcut definiscono quando gli spettatori salgono sul palcoscenico , ossia il momento in cui gli aspetti modificano il normale flusso del programma .
 
===Advice===
Riga 19:
quando un certo pointcut diventa valido . è importante notare che un advice può contenere esso stesso la definizione del pointcut che lo attiva. Un advice nella sua esecuzione può accedere ad eventuali
informazioni sui join point che lo compongono che il pointcut può
fornirgli . Sempre con riferimento alla metafora del teatro , gli advice definiscono cosa fanno gli spettatori sul palcoscenico.
 
===Aspect===
Riga 31:
====Join points====
 
un join point può essere , ad esempio, la chiamata di un metodo ; in aspectj , un join point che viene attivato dalla chiamata del metodo void faiqualcosa(int a) , si scrive come :
 
call (void faiqualcosa(int))
Riga 39:
execution(void faiqualcosa(int))
 
La differenza tra un join point di tipo execution e uno di tipo call è molto semplice : un join point di tipo call corrisponde alla chiamata di un metodo da parte di un altro metodo , mentre un join point di tipo execution corrisponde all' esecuzione del corpo del metodo . Normalmente un join poit di tipo call è pressoché equivalente a un join point di tipo execution ; a volte però non è così . Prendiamo ad esempio il caso della classe contenente il metodo main : in java, ,per convenzione , ogni programma deve comprendere una classe che implementi un metodo che abbia la seguente firma : public static void main(String[] args) . Tale metodo è il primo ad essere eseguito dalla java VM . Un join point definito come call (public static void main(String[] args)) non verrà mai raggiunto durante l'esecuzione di un programma java , a differenza del join point definito da execution (public static void main(String[] args)) . Questo accade perché ,anche se il metodo main verrà sicuramente eseguito , esso non viene mai chiamato da un altro metodo , in quanto sarà sempre il primo metodo ad essere eseguito .
Esistono inoltre molti altri modi per individuare dei join point nel flusso del programma :
 
Riga 50:
set (byte B.valore )
 
sono dei join point che denotano, rispettivamente , la lettura dell'attributo di tipo intero 'numero di un oggetto appartenente alla classe A e la scrittura di un attributo di tipo byte 'valore' di un oggetto appartenente alla classe B . Un join point di tipo initialization(), ,invece , corrisponde alla creazione di un oggetto .
 
initialization(B.new())
 
corrisponde alla creazione di un oggetto di classe B tramite un costruttore che non accetta parametri , mentre, ,ad esempio ,
 
initialization(C.new(String,int))
Riga 64:
adviceexecution()
 
Ci sono anche altri tipi di join point in aspectj , ma visto che il linguaggio è ancora in evoluzione , qui ci si è limitati a descrivere solo quelli più? frequentemente usati , che probabilmente saranno presenti anche nelle future versioni di aspectj , successive alla versione 1.1 cui l' autore fa riferimento .
In aspectj esistono inoltre delle espressioni che permettono di definire degli insiemi di join point;
l' espressione
Riga 76:
 
definisce invece un insieme di join point corrispondenti alla chiamata dei metodi di nome
doSomething che siano stati dichiarati come pubblici , che differiscono tra loro per il numero e il tipo degli argomenti ; inoltre , i suddetti metodi sono diversi anche per il tipo di dato che ritornano , che puo'può anche essere nullo (esempio : void doSomething(..) ) .
Un' altro esempio di espressione che codifica una proprietà definente un insieme di join point è
il seguente :
 
Riga 86:
====''Pointcut''====
 
Un pointcut è un join point , oppure una intersezione o una unione tra join point , o piu? informalmente , una certa situazione che si viene a creare durante l?esecuzione del programma . Un pointcut nella sua definizione comprende uno o piu? join point : un semplice esempio di pointcut definito a partire da un unico join point è il seguente :
 
pointcut pc() : call(void doSomething(int))
Riga 95:
 
mette a disposizione dell'advice una variabile int i che sarà inizializzata al valore del parametro intero passato al metodo
void doSomething(int n) . Vale la pena notare che il pointcut definito qui sopra è formalmente una intersezione , ossia un and logico tra due insiemi di join point definiti dalle due espressioni call (void doSomething(int)) e args( int i) : quest' ultima espressione indica tutti
i join point che accettano come input un unico parametro di tipo int . Facendo riferimento a pointcut che nelle loro definizioni hanno , tra gli altri , anche dei join point di tipo call , è possibile che essi indichino all' advice l'oggetto che effettua la chiamata e quello che la riceve . Prendiamo ad esempio il pointcut wait , così definito :
 
pointcut wait(A1 ac, B2 bd) : call(void wait()) && this(ac) && target(bd)
 
esso corrisponde a un oggetto appartenente alla classe A1 che , nel suo codice, effettui una chiamata di un metodo void wait() di un oggetto appartenente alla classe B2 ; detto oggetto viene identificato con bd ; ac , invece, si riferisce all'oggetto che effettua la chiamata .
è anche possibile definire un pointcut come un 'unione di due join point : tale poincut diventerà 'valido' quando l'esecuzione del programma raggiungera' uno qualsiasi (nella definizione si usa
l' OR logico) dei join point specificati . Ad esempio :
Riga 106:
poincut pt() : call(void calcola()) || execution(int moltiplica(int,int))
 
Tale pointcut coincide sia con la chiamata del metodo void calcola() , sia con l' esecuzione del corpo del metodo int moltiplica(int a , int b)
 
è anche possibile usare la negazione nella definizione di un pointcut :
Riga 112:
pointcut wait2(A1 ac, B2 bd) : call(void wait()) && !this(ac) && target(bd)
 
questo pointcut verrà attivato da una chiamata del metodo B2.wait() , purché la suddetta chiamata non sia effettuata da parte di un oggetto appartente alla classe A1 .
 
In generale , un pointcut genera dei join point . Basti pensare che nel corpo di un qualsiasi metodo , si puo'può verificare la creazione di un oggetto , la chiamata di un altro metodo , la gestione di un' eccezione . Idem dicasi per la gestione di un'eccezione , o per la creazione di un oggetto . In aspectj esistono pertanto delle apposite parole chiave per raggruppare i join point in insiemi in base al pointcut che li ha creati .
esse sono : cflow e cflowbelow .
per mostrare la differenza tra i due , prendiamo ad esempio il seguente frammento di codice :
 
pointcut ct() : call(void sum()) ;
pointcut fl() : cflow(ct) ;
 
il pointucut fl individua l'insieme di join point generati nell'esecuzione del metodo void sum , oltre al join point generato dalla chiamata del metodo sum() . il pointcut fl, ,inteso come insieme di join point , contiene cioè al suo interno il poincut ct . Invece , se definiamo il pointcut fl2 come :
 
pointcut fl2() : cflowbelow(ct) ;
 
questo pointcut fl2 corrispnderà all'insieme dei join point generati nell'esecuzione di void sum ,
ma non al join point generato dalla chiamata di void sum . il pointcut fl2 non contiene al suo interno il pointcut ct . cflow e cflowbelow sono due parole chiave usate frequentemente per definire pointcut che sono intersezioni di altri pointcut , ossia pointcut che usano nella loro definizione l' AND logico .
ad esempio :
 
pointcut restart() : cflowbelow(execution(void wait()))) && call(void resume(int)) ;
 
In questo caso , dall' insieme dei join point generati da void wait() vengono selezionati solo quelli generati da void resume() ; in pratica , questo pointcut diventerà valido solo quando void resume() verrà chiamato dall'interno del metodo void wait() oppure verra' chiamato dall' interno di un altro join point che è stato generato , direttamente o indirettamente , dall' esecuzione di void wait() . Altre due parole chiave usate di frequente nella definizione dei pointcut sono within e withincode.
Con within (nomeClasse) si indica l'insieme dei join point corrispondenti all' esecuzione di codice che sia , a livello di sorgenti , parte della classe nomeClasse . Ad esempio:
 
pointcut pi() : within(java.sql.*);
 
denota l'insime dei join point generati dal codice che è parte del package java.sql ; anologamente , wthincode denota l'insieme dei join point generati da codice che è parte di un certo metodo o di un certo costruttore . è quindi possibile definire un altro pointcut pi2 come
 
pointcut pi2() : withincode(void insert(Object o));
Riga 143:
====Advice====
 
Gli advice sono degli insiemi di istruzioni che vengono eseguiti prima , dopo oppure al posto di alcuni pointcut. In questo testo vengono trattati i primi due casi , visto che la semantica del terzo (advice di tipo 'around' ) è ancora in corso di definizione . Gli advice che vengono eseguiti prima che un pointcut diventi valido sono definiti dalla parola chiave before : prendiamo ad esempio il seguente codice :
 
 
Riga 161:
}
 
l' effetto di questo advice è di far stampare come messaggio a video , prima che il metodo termini, ,la parola '''arrivederci''' .
Un advice puo'può definire esso stesso il pointcut da cui dipende ; in altre parole , la seguente sintassi in aspectj è corretta :
 
after(): execution (void faQualcosa(..)) {tem.out.println(
}
 
Riga 172:
pointcut wait(A1 ac, B2 bd) : call(void wait()) && this(ac) && target(bd)
 
si puo'può scrivere il seguente advice :
 
before (A1 ac , B2 bd ) : wait(ac,bd) {
Riga 179:
}
 
Bisogna ricordare che in java un metodo può terminare regolarmente oppure lanciando un' eccezione : aspectj permette di distinguere questi due casi .
Si veda il seguente codice :
 
Riga 190:
}
 
quest' altro verra' eseguito solo se il metodo faiQualcosa ha gettato un' eccezione .
inoltre un advice del tipo after (..) returning puo'può avere a disposizione il dato che il metodo contenuto nel poincut ritorna , ad esempio è possibile scrivere
 
after (int a) returning : call(int moltiplica(int,int)) {
Riga 199:
}
 
analogamente , nel caso di un advice del tipo after(..) throwing è possibile avere a disposizione nel corpo dell'advice l'eccezione che il metodo ha gettato . Ad esempio , è possibile scrivere :
 
after (Exception e ) throwing : call(int moltiplica(int,int)) {
Riga 207:
====Aspetti====
 
Un aspetto modella una problematica trasversale dell' applicazione. Può contenere al suo interno definizioni di pointcut, advice, attributi e metodi, implementare un'interfaccia od estendere una classe; il viceversa ovviamente non vale.
Esistono aspetti astratti e aspetti concreti, esattamente così come esistono classi astratte e classi concrete; però, a differenza dell'OOP, nell'AOP un aspetto concreto non può estendere un altro aspetto concreto, ma solo un aspetto astratto.
Un esempio è il seguente :
Riga 277:
pointcut wait(A1 ac, B2 bd) : call(void wait()) && this(ac) && target(bd)
 
è possibile associare a ogni oggetto che genera un pointcut 'valido' un aspetto. Ossia, una istanza dell'aspetto viene creata ogni volta che il flusso del programma raggiunge il pointcut wait e all'oggetto in esecuzione (this, in Java) non è gia associata un' istanza dell'aspetto. In AspectJ questo si scrive come:
 
aspect nomeaspetto perthis(wait(A1 ac, B2 bd)) { }