Upload
jehane-marty
View
102
Download
0
Embed Size (px)
Citation preview
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 1 -
Seconde partie
Un exemple de programmation orientée Aspect
avec AspectJ
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 2 -
AspectJ est
• un langage• aspects, points de jointure, advices, … sont des extensions
syntaxiques de Java
• une approche par transformation de code• compilateur ajc (remplace javac) => nécessite le code source
• les .class générés par ajc sont compatibles avec toute JVM
• statique => performant mais peu flexible
• supporté par des IDE (emacs, JBuilder, Forte 4J, Eclipse)
• open source et gratuit
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 3 -
Un éditeur de figure
operations that move elements
factory methodsDisplay
*
2Point
getX()getY()setX(int)setY(int)moveBy(int, int)
Line
getP1()getP2()setP1(Point)setP2(Point)moveBy(int, int)
Figure
makePoint(..)makeLine(..)
FigureElement
moveBy(int, int)
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 4 -
Un éditeur de figure
class Line implements FigureElement{ private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } void moveBy(int dx, int dy) { ... }}
class Point implements FigureElement { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; } void moveBy(int dx, int dy) { ... }}
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 5 -
a Line
a Point
Où sont les points de jointure (join points) ?
returning or throwing
dispatch
dispatch
a method call
returning or throwinga method execution
returning or throwinga method execution
Un appel : l.moveBy(2, 2)
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 6 -
Les coupes (pointcuts)
• Un moyen d’identifier un ensemble de points de jointure
• Une coupe est un prédicat sur les points de jointure
• Primitives de coupes disponibles :• call, execution
• initialization, preinitialization, staticinitialization
• get, set
• handler
• within, withincode
• cflow, cflowbelow
• this, target, args
• ...
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 7 -
Combinaison des primitives de coupe
or
a “void Line.setP2(Point)” call
a “void Line.setP1(Point)” call
call(void Line.setP1(Point)) || call(void Line.setP2(Point));
Utilisation de &&, || et ! comme pour les prédicats
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 8 -
Type d’advices
• Des actions supplémentaires à faire lorsqu’une coupe est identifiée
• before pour ajouter des actions avant
• after pour ajouter des actions après• after returning sur retour normal
• after throwing sur retour avec erreur
• around pour prendre le control sur l’exécution du point de jointure
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 9 -
Coupe anonyme ou non dans un advice
pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));
Nom de coupe Paramètres de coupe
after() returning: call(void Line.setP1(Point)) || call(void Line.setP2(Point)) { Display.update(); }
after() returning: move() { Display.update(); }
Coupe anonyme
Utilisation de la coupe définie
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 10 -
Exemple d’aspect : Rafraîchissement d’image
• collection of figure elements• that move periodically
• must refresh the display as needed
• complex collection
• asynchronous events
we will initially assume just a single display
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 11 -
Rafraîchissement sans et avec AspectJ
class Line { private Point p1, p2;
Point getP1() { return p1; } Point getP2() { return p2; }
void setP1(Point p1) { this.p1 = p1; Display.update(); } void setP2(Point p2) { this.p2 = p2; Display.update(); }}
aspect DisplayUpdating {
pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));
after() returning: move() { Display.update(); }}
DisplayUpdatingV1
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 12 -
Les coupes peuvent concernées plusieurs classes
aspect DisplayUpdating {
pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int));
after() returning: move() { Display.update(); }}
class Line { private Point p1, p2;
Point getP1() { return p1; } Point getP2() { return p2; }
void setP1(Point p1) { this.p1 = p1; Display.update(); } void setP2(Point p2) { this.p2 = p2; Display.update(); } void moveBy(int dx, int dy) { … }}
class Point {
private int x = 0, y = 0;
int getX() { return x; } int getY() { return y; }
void setX(int x) { this.x = x; Display.update(); } void setY(int y) { this.y = y; Display.update(); } void moveBy(int dx, int dy) { … }}
DisplayUpdatingV2
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 13 -
Primitive de coupe “this”/“target”this/target(VarName | TypeName) permet de : - tester dynamiquement le type de l’objet courant/de la cible
(restreint la coupe)this(Point), target(Line)
- récupérer l’objet courant/la cible du point de jointure en cours (ne restreint pas la coupe)
this(myLine), target(myPoint)
Valeur de variable extraite de la droite vers la gauche du ‘:’• du target vers la coupe définie par l’utilisateur
• de la coupe vers l’advice, et donc dans le corps de l’advice
pointcut move(Line l): target(l) && (call(void Line.setP1(Point)) || call(void Line.setP2(Point)));
after(Line line) returning: move(line) { ... }
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 14 -
Gestion du contexte utilisant “target”
aspect DisplayUpdating {
pointcut move(FigureElement figElt): target(figElt) && (call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int)));
after(FigureElement fe) returning: move(fe) { Display.update(fe); }}
figElt est lié à FigureElement dans la coupe “move”fe est lié à FigureElement dans l’advice
DisplayUpdatingV3
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 15 -
Primitive de coupe “args”
aspect PointBoundsPreCondition { before(int newX): call(void Point.setX(int)) && args(newX) { assert newX >= MIN_X; assert newX <= MAX_X; } before(int newY): call(void Point.setY(int)) && args(newY) { assert newY >= MIN_Y; assert newY <= MAX_Y; }}
aspect PointBoundsPostCondition { after(Point p, int newX) returning: call(void Point.setX(int)) && target(p) && args(newX) { assert p.getX() == newX; } after(Point p, int newY) returning: call(void Point.setY(int)) && target(p) && args(newY) { assert p.getY() == newY; }}
Vérification de contratsMême principe que target et this maispour les paramètres du point de jointure
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 16 -
Méthode spéciale “proceed”
Utilisée dans les advices de type “around”ReturnType around(T1 arg1, T2 arg2, …)
La méthode proceedReturnType proceed(T1, T2, …)
Permet d’exécuter ce qui aurait été exécuté sil’advice n’avait pas été défini
Même type de paramètres et même type de retour
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 17 -
Méthode spéciale “proceed”
aspect PointBoundsEnforcement { void around(int newX): call(void Point.setX(int)) && args(newX) { proceed( clip(newX, MIN_X, MAX_X) ); } void around(int newY): call(void Point.setY(int)) && args(newY) { proceed( clip(newY, MIN_Y, MAX_Y) ); } private int clip(int val, int min, int max) { return Math.max(min, Math.min(max, val)); }}
Gestion des bornes
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 18 -
Déclaration de méthodes et d’attributs
aspect PointCaching {
private MyLookupTable cache = new MyLookupTable();
Point around(int x, int y): call(Point.new(int, int)) && args(x, y) { Point ret = cache.lookup(x, y); if (ret == null) { ret = proceed(x, y); cache.add(x, y, ret); } return ret; }}
Gestion d’un cache
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 19 -
aspect DisplayUpdating {
private Display FigureElement.display;
static void setDisplay(FigureElement fe, Display d) { fe.display = d; }
pointcut move(FigureElement figElt): <as before>;
after(FigureElement fe): move(fe) { fe.display.update(); }}
Un afficheur par element de figure
DisplayUpdating v4
display est un attribut dans les objets de type FigureElement, mais :• appartient à l’aspect DisplayUpdating
• DisplayUpdating doit fournir getter/setter (appelé dans le code de setup)
Déclaration de méthodes et d’attributs
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 20 -
Généricité des coupes
target(Point)target(graphics.geom.Point)target(graphics.geom.*) tout type dans graphics.geomtarget(graphics..*) tout type dans un sous-package
de graphics
call(void Point.setX(int))call(public * Point.*(..)) toute méthode publique de Pointcall(public * *(..)) toute méthode publique
de n’importe quel type
call(void Point.setX(int))call(void Point.setY(*))call(void Point.set*(*))call(void set*(*)) tout mutateur
call(Point.new(int, int))call(new(..)) tout constructeur
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 21 -
Access réflexif au point de jointure courant
Disponible dans les advices
thisJoinPoint.getSignature(), thisJoinPoint.getArgs(), ...
aspect PublicErrorLogging {
Logger log = Logger.global;
pointcut publicInterface(): call(public * graphics..*.*(..));
after() throwing (Error e): publicInterface() { Method m = thisJoinPoint.getSignature(); log.throwing( m.getDeclaringType().getName(), m.getName(), e); }}
thisJoinPoint permet de savoir où l’advice s’exécute
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 22 -
Initialization/ preinitialization/ staticinitialization ( Pointcut )
initialization(Foo.new(int))l’initialisation qui débute avec le constructeur Foo.new(int)
preinitialization(Foo.new(int)) comme initialisation mais avant que le constructeur de super soit appelé
staticinitialization(Foo.new(int))quand le type Foo est initialisé après le chargement de la classe
D’autres primitives de coupes : contrôle des initialisations
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 23 -
D’autres primitives de coupes
within( TypeName ) withincode( MemberSignature )
Tout point de jointure tel que : - le code en cours d’exécution est défini dans le type TypeName - le code en cours d’exécution est défini dans la méthode ou contructeur dont la signature est MemberSignature
get( int Point.x ) set( int Point.x )
Accès à un attribut en lecture/écriture
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 24 -
Exemple avec withincode : gestion des constructions de figures
class Figure { public Line makeLine(Line p1, Line p2) { new Line... } public Point makePoint(int x, int y) { new Point... } ...}
aspect FactoryEnforcement { pointcut illegalNewFigElt(): (call(Point.new(..)) || call(Line.new(..))) && !withincode(* Figure.make*(..));
before(): illegalNewFigElt() { throw new Error("Use factory method instead."); }}
Assurer que la création d’une figure se fait uniquement en utilisant les méthodes de fabrique
Erreur d’exécution
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 25 -
class Figure { public Line makeLine(Line p1, Line p2) { new Line... } public Point makePoint(int x, int y) { new Point... } ...}
aspect FactoryEnforcement { pointcut illegalNewFigElt(): (call(Point.new(..)) || call(Line.new(..))) && !withincode(* Figure.make*(..));
declare error: illegalNewFigElt(): "Use factory method instead."; }}
Erreur de compilation
Assurer que la création d’une figure se fait uniquement en utilisant les méthodes de fabrique
Exemple avec withincode : gestion des constructions de figures
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 26 -
class Figure { public Line makeLine(Line p1, Line p2) { new Line... } public Point makePoint(int x, int y) { new Point... } ...}
aspect FactoryEnforcement { pointcut illegalNewFigElt(): call(FigureElement+.new(..)) && !withincode(* Figure.make*(..));
declare error: illegalNewFigElt(): "Use factory method instead."; }}
Erreur de compilation
Tous les sous-types
Assurer que la création d’une figure se fait uniquement en utilisant les méthodes de fabrique
Exemple avec withincode : gestion des constructions de figures
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 27 -
all join points on this slide are within the control flow of
this join point
a Point
a Line
a Point
Flot de contrôle et point de jointure
Un appel : l.moveBy(2, 2)
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 28 -
cflow( Pointcut )tous les points de jointure dans le flot de contrôle du point de jointure Pointcut
cflowbelow( Pointcut )tous les points de jointure au dessous du flot de contrôle du point de jointure Pointcut
D’autres primitives de coupes
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 29 -
Exemple avec cflowbelow : contrôle des mouvements de plus haut niveau (top-level)
DisplayUpdating v5
aspect DisplayUpdating {
pointcut move(FigureElement fe): target(fe) && (call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int)));
pointcut topLevelMove(FigureElement fe): move(fe) && !cflowbelow(move(FigureElement));
after(FigureElement fe) returning: topLevelMove(fe) { Display.update(fe); }}
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 30 -
Composition d’aspects
Qu’est ce qu’il se passe si 2 « advices » sont appliqués au même point de jointure ?
aspect Security { before(): call(public *(..)) { if (!Policy.isAllowed(thisJoinPoint)) throw new SecurityExn(); }
}
aspect Logging { before(): logged() { System.err.println("Entering " + thisJoinPoint); } pointcut logged(): call(void troublesomeMethod());}
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 31 -
Composition d’aspects
• Ordre indéfini sauf • dans un même aspect, dans les sous aspects,
• en déclarent une règle de précédence
aspect Security { before(): call(public *(..)) { if (!Policy.isAllowed(thisJoinPoint)) throw new SecurityException(); } declare precedence: Security, *;}
aspect Logging { pointcut logged(): call(void troublesomeMethod()); before(): logged() { System.err.println("Entering " + thisJoinPoint); }}
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 32 -
Réutilisation d’aspects : aspects abstraits et héritage
abstract aspect Tracing { abstract pointcut trace();
before(): trace() { TraceSupport.traceEntry(thisJoinPoint); } after(): trace() { TraceSupport.traceExit(thisJoinPoint); }}
aspect PointTracing { pointcut trace(): within(Point) && execution(* *(..)); before(): trace() { TraceSupport.traceEntry(thisJoinPoint); } after(): trace() { TraceSupport.traceExit(thisJoinPoint); }}
aspect PointTracing extends Tracing {
pointcut trace(): within(Point) && execution(* *(..));}
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 33 -
• plug in:
• unplug:
“Plug & debug”
ajc Point.java Line.java
ajc Point.java Line.java TraceSupport.java Tracing.java
• Activer/désactiver la trace sans éditer les classes
• Pas de coût d’exécution quand désactivé
Séparation des préoccupations
(c) 2004, Audrey Occello, LF8 MOC. . - 34 -
Conclusion
• Bonne modularité
• Code + naturel, + petit, - mélangé
• Maintenance et évolution + facile• application + facile à comprendre, à débugger, à changer
• Réutilisation facilitée• ajout/retrait d’aspects
• aspects abstraits