Séparation des préoccupations (c) 2004, Audrey Occello, LF8 MOC.. - 1 - Seconde partie Un exemple...

34
Séparation des préoccupations (c) 2004, Audrey Occello, LF8 MOC. . - 1 - Seconde partie Un exemple de programmation orientée Aspect avec AspectJ

Transcript of Séparation des préoccupations (c) 2004, Audrey Occello, LF8 MOC.. - 1 - Seconde partie Un exemple...

Page 1: 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. . - 1 -

Seconde partie

Un exemple de programmation orientée Aspect

avec AspectJ

Page 2: 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

Page 3: 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. . - 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)

Page 4: 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. . - 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) { ... }}

Page 5: 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. . - 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)

Page 6: 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. . - 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

• ...

Page 7: 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. . - 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

Page 8: 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. . - 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

Page 9: 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. . - 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

Page 10: 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. . - 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

Page 11: 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. . - 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

Page 12: 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. . - 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

Page 13: 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. . - 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) { ... }

Page 14: 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. . - 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

Page 15: 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. . - 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

Page 16: 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. . - 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

Page 17: 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. . - 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

Page 18: 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. . - 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

Page 19: 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. . - 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

Page 20: 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. . - 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

Page 21: 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. . - 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

Page 22: 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. . - 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

Page 23: 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. . - 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

Page 24: 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. . - 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

Page 25: 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. . - 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

Page 26: 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. . - 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

Page 27: 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. . - 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)

Page 28: 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. . - 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

Page 29: 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. . - 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); }}

Page 30: 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. . - 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());}

Page 31: 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. . - 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); }}

Page 32: 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. . - 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(* *(..));}

Page 33: 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. . - 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é

Page 34: 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. . - 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