© 2006 by andy clement, ibm: made available under the epl v1.0 aspect-oriented programming with...

119
© 2006 by Andy Clement, IBM: made available under the EPL v1.0 Aspect-Oriented Programming with AspectJ Andy Clement AspectJ Committer, IBM UK ®

Upload: augusta-craig

Post on 25-Dec-2015

215 views

Category:

Documents


0 download

TRANSCRIPT

© 2006 by Andy Clement, IBM: made available under the EPL v1.0

Aspect-Oriented Programming with AspectJ

Andy ClementAspectJ Committer, IBM UK

®

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 2

outlineI AOP and AspectJ overview

• motivation for AOP• problems, basic concepts, context

II AspectJ tutorial • language mechanisms• writing aspects• Java5• using the eclipse tools (demo…)

III Adopting AspectJ

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 3

good modularity

XML parsing in org.apache.tomcat• red shows relevant lines of code• nicely fits in one box

XML parsing

Courtesy of PARC

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 4

good modularityURL pattern matching

URL pattern matching in org.apache.tomcat• red shows relevant lines of code• nicely fits in two boxes (using inheritance)

Courtesy of PARC

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 5

problems like…logging is not modularized

where is logging in org.apache.tomcat• red shows lines of code that handle logging • not in just one place• not even in a small number of places Courtesy of PARC

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 6

the problem of crosscutting concerns

• critical aspects of large systems don’t fit in traditional modules• logging, error handling• synchronization• security• memory management• performance optimizations

logging, security, optimizations

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 7

the problem of crosscutting concerns

• tangled code has a cost• difficult to understand• difficult to change• increases with size of system• maintenance costs are huge

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 8

the AOP idea• crosscutting is inherent in complex

systems

• crosscutting concerns• have a clear purpose• have a natural structure

• so, let’s capture the structure of crosscutting concerns explicitly...

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 9

this tutorial is about...• using AOP and AspectJ to:

• improve the modularity of crosscutting concerns

• aspects are two things• concerns that crosscut [design level]• a programming construct [implementation

level]• enables crosscutting concerns

to be captured in modular units

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 10

AspectJ is…

• a small and well-integrated extension to Java• outputs .class files compatible with any JVM• all Java programs are AspectJ programs

• a general-purpose AO language• just as Java is a general-purpose OO language

“an aspect-oriented extension to Java that supports general-purpose aspect-oriented programming”

TM

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 11

AspectJ is…

• includes IDE support• AJDT support for Eclipse

• freely available implementation• compiler & tools are Open Source

• active user community• [email protected]

“an aspect-oriented extension to Java that supports general-purpose aspect-oriented programming”

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 12

• Example: java code base with 10,000 files and 500 developers

• Comparison of capturing policies with ‘regular’ techniques or with AspectJ• logging (yey!)• error handling• profiling policies

AspectJ applied to a large middleware system

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 13

What’s the difference?

traditional system aop system

logging

security

• Reduced scattering

• Reduced tangling

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 14

Eliminating tanglingtry { if (!removed)

entityBean.ejbPassivate(); setState( POOLED );} catch (RemoteException ex ) { FFDCEngine.processException( ex,”EBean.passivate()”,”237”, this); destroy(); throw ex;} finally { if (!removed && statisticsCollector != null ) { statisticsCollector. recordPassivation(); } removed = false; beanPool.put( this ); if (Logger.isEnabled) { Logger.exit(tc,”passivate”); }}

try { if (!removed)

entityBean.ejbPassivate(); setState( POOLED );} catch (RemoteException ex ) { destroy(); throw ex;} finally { removed = false; beanPool.put( this );}

Crosscutting concernsextracted

Example: Code to handle EJB Entity bean

passivation

before after

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 15

AspectJ applied to a large middleware system

existing policy implementations

• affect every file• 5-30 page policy

documents• applied by developers

• affect every developer• must understand policy

document

policies implemented with AspectJ

• one reusable crosscutting module• policy captured explicitly• applies policy uniformly for

all time

• written by central team• no burden on other 492

developers

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 16

AspectJ applied to a large middleware system

existing policy implementations

• repeat for new code assets

• awkward to support variants• complicates product

line

• don’t even think about changing the policy!

policies implemented with AspectJ

• automatically applied to new code

• easy plug and unplug• simplifies product line

issues

• changes to policy happen in one place

© 2006 by Andy Clement, IBM: made available under the EPL v1.0

Part II

tutorial

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 18

language mechanisms

• goal: present basic mechanisms• using one simple example

• emphasis on what the mechanisms do• small scale motivation

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 19

basic mechanisms• ONE overlay onto Java

• dynamic join points • “points in the execution” of Java

programs

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 20

basic mechanisms• FOUR small additions to Java

• pointcuts• pick out join points and values at those

points • primitive, user-defined pointcuts

• advice• additional action to take at join points in a

pointcut• inter-type declarations• aspect

• a modular unit of crosscutting behavior• comprised of advice, inter-type, pointcut,

field, constructor, and method declarations

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 21

a simple figure editor

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)

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 22

a simple figure editorclass 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) { ... }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 23

display updating

• collection of figure elements• that move periodically• must refresh the display as

needed

we will initially assume just a single display

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 24

join pointskey points in dynamic call

graph

Method executionMethod call

Line Point 1 Point 2imagine

l.moveBy(2,2)

p1.moveBy(2,2)

p2.moveBy(2,2)

Join points

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 25

join point terminology

• All kinds of events could be join points but AspectJ exposes this set: • method & constructor call• method & constructor execution• field get & set• exception handler execution• static & dynamic initialization

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 26

call(void Line.setP1(Point))

primitive pointcuts

• a pointcut identifies some set of join points• can match or not match any given join point,

and• optionally, can pull out some of the values

(‘context’) at that join point

matches if the join point is a method call with this signature ‘void Line.setP1(Point)’

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 27

pointcut composition

• pointcuts can be composed• using &&, || and !

matches either a call to ‘void Line.setP1(Point)’ or a call to ‘void Line.setP2(Point)’

call(void Line.setP1(Point)) || call(void Line.setP2(Point));

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 28

user-defined pointcuts

user-defined (aka named) pointcuts• can be used in the same way as primitive

pointcuts

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

name parameters

more on parameters and how pointcut can expose values at join points in a

few slides…

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 29

pointcutsprimitive pointcuts are - call, execution - this, target, args - get, set - within, withincode - handler - cflow, cflowbelow - initialization, staticinitialization

and with AspectJ5 - @annotation, @within, @withincode, @this, @target, @args

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 30

After Advice

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

after() returning: move() { <code here runs after each move> }

after advice

• Advice• additional action to take at join points in

a pointcut l.setP1(p)

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 31

a simple aspect• DisplayUpdating version1

• an aspect defines a ‘special module’ that can crosscut other classes

aspect DisplayUpdating {

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

after() returning: move() { Display.update(); }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 32

without AspectJ

• what you would expect• update calls are tangled through the code• “what is going on” is less explicit

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(); }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 33

pointcuts

• can cut across multiple classes…

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int));

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 34

pointcuts

• can use interface signatures

pointcut move(): 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));

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 35

a multi-class aspect

• DisplayUpdating version2aspect DisplayUpdating {

pointcut move(): 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() returning: move() { Display.update(); }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 36

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) { <fe is bound to the figure element> }

using values at join points

• pointcuts can explicitly expose certain values• advice can use those values

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 37

explaining pointcut parameters…

• variable is bound by user-defined pointcut declaration• pointcut supplies value for variable• value is available to all users of user-defined pointcutpointcut

parameters pointcut move(Line l): target(l) && (call(void Line.setP1(Point)) || call(void Line.setP2(Point)));

after(Line line) returning: move(line) { <line is bound to the line> }

typed variable in place of type name

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 38

explaining advice parameters…

• variable is bound by advice declaration• pointcut supplies value for variable• value is available in advice body

pointcut move(Line l): target(l) && (call(void Line.setP1(Point)) || call(void Line.setP2(Point)));

after(Line line) returning: move(line) { <line is bound to the line> }

typed variable in place

of type nameadvice parameters

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 39

explaining parameters…• Traditional method invocation

• parameter values supplied at call site• With AspectJ pointcuts

• join point provides values for parameters• With AspectJ advice

• pointcuts provide values for parameters

pointcut move(Line l): target(l) && (call(void Line.setP1(Point)) || call(void Line.setP2(Point)));

after(Line line) returning: move(line) { <line is bound to the line> }

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 40

target() primitive pointcut

target( TypeName | FormalReference )

does two things: - exposes target - matches any join point at which target object is an

instance of type name

target(Point)target(Line)target(FigureElement)

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 41

pointcuts

• can expose values at join points 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)));

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 42

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); }}

context & multiple classes

• DisplayUpdating version3

Taking the FigureElement into account

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 43

So far…

• Capturing our update policy, with and without AspectJ

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 44

without AspectJ

• Original programclass Line { 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 {

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) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 45

without AspectJ

• DisplayUpdating version1• Tracking changes in Lines

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;

} void setY(int y) { this.y = y;

} void moveBy(int dx, int dy) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 46

without AspectJ

• DisplayUpdating version2• Extending it to also

support changes in Points

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) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 47

without AspectJ• DisplayUpdating version 3• Recording which object

actually changed• no locus of “display updating”

• evolution is cumbersome• changes in all classes• have to track & change all

callers

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; Display.update(this); } void setP2(Point p2) { this.p2 = p2; Display.update(this); } 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(this); } void setY(int y) { this.y = y; Display.update(this); } void moveBy(int dx, int dy) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 48

with AspectJclass Line { 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 {

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) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 49

with AspectJ

• DisplayUpdating version1

aspect DisplayUpdating {

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

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;

} void setP2(Point p2) { this.p2 = p2;

} 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;

} void setY(int y) { this.y = y;

} void moveBy(int dx, int dy) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 50

with AspectJ

• DisplayUpdating version2

aspect DisplayUpdating {

pointcut move(): 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() 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;

} void setP2(Point p2) { this.p2 = p2;

} 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;

} void setY(int y) { this.y = y;

} void moveBy(int dx, int dy) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 51

with AspectJ• DisplayUpdating version3• clear display updating module

• all changes in single aspect• evolution is modular

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); }}

class Line { 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 {

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) { … }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 52

aspects crosscut classesaspect modularity cuts across class

modularity

DisplayUpdating

Display

*

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)

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 53

advice is• additional action to take at join points• before

• before proceeding at join point

• after returning• after a join point completes normally

• after throwing• when a join point completes abnormally

• after• when a join point completes (either normally or abnormally)

• around• on arrival at join point gets explicit control over when & if

program proceeds

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 54

contract checking

• What can you use these advice kinds for?

• pre-conditions• check whether parameter is valid

• post-conditions• check whether values were set

• condition enforcement• force parameters to be valid

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 55

pre-condition: before adviceaspect PointBoundsPreCondition { before(int newX): call(void Point.setX(int,long)) && 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; }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 56

post-condition: after adviceaspect 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; }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 57

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)); }}

condition enforcement: around advice

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 58

special method: proceed

• for each around advice with the signaturereturnType around(T1 arg1, T2 arg2, …)

• there is a special method with the signature

returnType proceed(T1, T2, …)

• available only in around advice• means “run what would have run if this

around advice had not been defined”

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 59

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; }}

extra: caching with around advice

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 60

property-based crosscutting

• crosscuts of methods with a common property• public/private, return a certain value, in a particular package

• logging, debugging, profiling• log on entry to every public method

package com.parc.print;public class C1 { … public void foo() { A.doSomething(…); … }}

package com.parc.scan;public class C2 { … public int frotz() { A.doSomething(…); } public int bar() { A.doSomething(…); }}

package com.parc.copy;public class C3 { … public String s1() { A.doSomething(…); }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 61

property-based crosscutting

consider code maintenance• another programmer adds a public method

• i.e. extends public interface – this code will still work• another programmer reads this code

• “what’s really going on” is explicit

aspect PublicErrorLogging {

Logger log = Logger.global;

pointcut publicInterface(): call(public * com.bigboxco..*.*(..));

after() throwing (Error e): publicInterface() { log.warning(e); }}

neatly captures public interface of my packages

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 62

wildcarding in pointcutstarget(Point)target(graphics.geom.Point)target(graphics.geom.*) any type in graphics.geomtarget(graphics..*) any type in any sub-package of graphics

call(void Point.setX(int))call(public * Point.*(..)) any public method on Pointcall(public * *(..)) any public method on any type

call(void Point.setX(int))call(void Point.setY(*))call(void Point.set*(*))call(void set*(*)) any setter

call(Point.new(int, int))call(new(..)) any constructor

“*” is wild card“..” is multi-part wild card

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 63

special value: thisJoinPoint

• Reflective access to the join point from advice

• Methods like:Signature getSignature()Object[] getArgs()

• Related ‘thisJoinPointStaticPart’ provides only statically determinable portions• better performing

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 64

using thisJoinPointaspect PublicErrorLogging {

Logger log = Logger.global;

pointcut publicInterface(): call(public * com.bigboxco..*.*(..));

after() throwing (Error e): publicInterface() { log.throwing( thisJoinPoint.getSignature().getDeclaringType().getName(), thisJoinPoint.getSignature().getName(), e); }}

using thisJoinPoint makes it possible for the advice to recover information about where it is running

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 65

other primitive pointcuts

• any join point at which• currently executing object is an instance of type name• currently executing code is contained within type name• currently executing code is specified methods or constructors

• field reference or assignment join points

this( TypeName ) within( TypeName )withincode( MemberSignature )

get( FieldSignature ) set( FieldSignature )

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 66

fine-grained protection

• Ensure that creation of figure elements is done through the factory methods

class Figure { public Line makeLine(Line p1, Line p2) { new Line... } public Point makePoint(int x, int y) { new Point... } ...}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 67

fine-grained protection

• Easy to police with a run time error• but can we do better?

aspect FactoryEnforcement { pointcut illegalNewFigElt(): (call(Point.new(..)) || call(Line.new(..))) && !withincode(* Figure.make*(..));

before(): illegalNewFigElt() { throw new Error("Use factory method instead."); }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 68

fine-grained protection• Can report as a compile time error

• Using ‘declare warning/error’

• Must be a statically resolvable pointcut

aspect FactoryEnforcement { pointcut illegalNewFigElt(): (call(Point.new(..)) || call(Line.new(..))) && !withincode(* Figure.make*(..));

declare error: illegalNewFigElt(): "Use factory method instead."; }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 69

fine-grained protection

• More generally applicable• policing all figure elements

aspect FactoryEnforcement { pointcut illegalNewFigElt(): call(FigureElement+.new(..)) && !withincode(* Figure.make*(..));

declare error: illegalNewFigElt(): "Use factory method instead."; }}

‘+’ means this type and all

subtypes

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 70

fine-grained protection

• ‘Local enforcement’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) { ... }

static aspect SetterEnforcement { declare error: set(Point Line.*) && !withincode(void Line.setP*(Point)) "Use setter method, even inside Line class"; }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 71

more primitive pointcuts• method/constructor execution join points

execution(void Point.setX(int))

• object initialization join pointsinitialization(Point.new(int))

• class initialization join points (as the class is loaded)

staticinitialization(Point)

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 72

join points: call and execution

Method executionMethod call

Line Point 1 Point 2imagine

l.moveBy(2,2)

p1.moveBy(2,2)

p2.moveBy(2,2)

Join points

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 73

other primitive pointcuts cflow(pointcut)• “all join points in the

dynamic control flow of any join point picked out by the specified pointcut”

cflowbelow(pointcut)• “all join points in the

dynamic control flow below any join point picked out by the specified pointcut”

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 74

only top-level moves

• DisplayUpdating version4aspect 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); }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 75

Java5…• Java5 introduced many changes to the Java language

• Generics, enum types, varargs support, covariance, autoboxing, annotation types

• AspectJ5 supports all of these features• The AspectJ language has been extended to enable

exploitation of these new features

• For all the details: see the AspectJ5 quick reference guide and AspectJ5 developers notebook

• http://eclipse.org/aspectj

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 76

Java5: Annotations

• Java 5 introduces annotations to the Java language

• Annotations are metadata that can be attached to various Java language constructs• methods, fields, types, parameters, constructors

• AspectJ5 extends the pointcut language to support join point matching based to annotations

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 77

Java5: matching on annotations

• Suppose methods that ‘move’ figure elements are tagged with annotations

@interface MovingOperation {}

class Line implements FigureElement{ private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } @MovingOperation void setP1(Point p1) { this.p1 = p1; } @MovingOperation void setP2(Point p2) { this.p2 = p2; } …

Defining an annotation

Marking methods with the

annotation

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 78

Java5: matching on annotations

aspect DisplayUpdating { pointcut move(FigureElement fe): target(fe) && call(@MovingOperation * *(..));

after(FigureElement fe) returning: move(fe) { Display.update(fe); }}

• Suppose methods that ‘move’ figure elements are tagged with annotations

• Pointcuts can now be written to match on annotation properties of the pointcut rather than the name

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 79

Java5• New pointcut primitives have been

created to make working with annotated join points even easier• @within, @withincode, @this, @target,

@args, @annotation

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 80

inter-type declarations

• like member declarations...

long l = 37;void m() { ... }

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 81

inter-type declarations

• like member declarations, but with a TargetType

long TargetType.l = 37;void TargetType.m() { ... }

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 82

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(fe); }}

one display per figure element

• DisplayUpdating version5• The aspect makes an inter-type

declaration of a display field onto all FigureElements

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 83

common ITD field idiom• the display field…

…is a field in objects of type FigureElement……but belongs to DisplayUpdating aspect

• So, DisplayUpdating should provide getter/setter

aspect DisplayUpdating {

private Display FigureElement.display;

public static void setDisplay(FigureElement fe, Display d) { fe.display = d; }

pointcut move(FigureElement figElt): <as before>;

after(FigureElement fe): move(fe) { fe.display.update(fe); }}

private with respect to

enclosing aspect declaration

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 84

one-to-many• DisplayUpdating version6

• A figurelement knows about multiple Displaysaspect DisplayUpdating {

private List FigureElement.displays = new LinkedList();

public static void addDisplay(FigureElement fe, Display d) { fe.displays.add(d); } public static void removeDisplay(FigureElement fe, Display d) { fe.displays.remove(d); }

pointcut move(FigureElement figElt): <as before>;

after(FigureElement fe): move(fe) { Iterator iter = fe.displays.iterator(); ... }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 85

inheritance & specialization• pointcuts can have additional advice

• aspect with• concrete pointcut• perhaps no advice on the pointcut

• in figure editor•move() can have advice from multiple

aspects• module can expose certain well-defined

pointcutsa ‘pointcut library’

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 86

inheritance & specialization• abstract pointcuts can be specialized

• aspect with• abstract pointcut• concrete advice on the abstract pointcut

• Abstract aspects can be packaged and extended by users desiring their capability

an ‘aspect library’

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 87

role types and reusable aspects

abstract aspect Observing { protected interface Subject { } protected interface Observer { }

private List Subject.observers = new ArrayList(); public void addObserver(Subject s, Observer o) { ... } public void removeObserver(Subject s, Observer o) { ... } public static List getObservers(Subject s) { ... }

abstract pointcut changes(Subject s);

after(Subject s): changes(s) { Iterator iter = getObservers(s).iterator(); while ( iter.hasNext() ) { notifyObserver(s, ((Observer)iter.next())); } } abstract void notifyObserver(Subject s, Observer o);}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 88

this is the concrete reuse• DisplayUpdating version7

• Just an example of subject/observer patternaspect DisplayUpdating extends Observing {

declare parents: FigureElement implements Subject; declare parents: Display implements Observer;

pointcut changes(Subject s): target(s) && (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)));

void notifyObserver(Subject s, Observer o) { ((Display)o).update(s); }}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 89

advice precedence

• what happens if two pieces of advice apply to the same join point?aspect Security {

before(): call(public * *(..)) { if (!Policy.isAllowed(tjp)) throw new SecurityExn(); } }

aspect Logging { before(): logged() { System.err.println( "Entering " + tjp); } pointcut logged(): call(void troublesomeMethod());}tjp means

‘thisJoinPoint’

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 90

advice precedence

• order is undefined, unless...• in the same aspect,• in subaspect, or• using declare

precedenceaspect Security { before(): call(public *(..)) { if (!Policy.isAllwed(tjp)) throw new SecurityExn(); } declare precedence: Security, *;}

aspect Logging { before(): logged() { System.err.println( "Entering " + tjp); } pointcut logged(): call(void troublesomeMethod());}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 91

Annotation Style Development• AspectJ5 supports an alternative

‘annotation based’ style of aspect declaration• For a subset of the AspectJ language• Enables aspect development in pure-Java IDEs

• Aspect is pure-java, compiled with Java5 and then given to the AspectJ weaver

• Styles can be mixed within an application (or even within a source file!)

• The intent is that the semantics are identical, regardless of the source style chosen to express the aspect

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 92

import org.aspectj.lang.annotation.*;

@AspectPublic class Tracing {…}

Annotation style: defining an aspect

• In code style

• In annotation style, a class is annotated to indicate it is an aspect

public aspect Tracing {…}

Don’t forget the import

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 93

Annotation style: pointcuts• Unsurprisingly, pointcuts and advice declarations

involve these annotations• @Pointcut @Before @After @AfterReturning @AfterThrowing @Around

• The @Pointcut annotation is attached to a method declaration• the annotation value is the pointcut text

pointcut anyCall(): call(* *(..));

@Pointcut(“call(* *(..))”)void anyCall()

pointcut listCalls(MyList list): call(* *(int)) && target(list);

@Pointcut(“call(* *(int)) && target(list)”)void listCalls(MyList list)

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 94

Annotation style: type references

• In code style• type references are resolved in the context of any types

imported into the source file

• In annotation style• type references need to be resolved without that

information therefore have to be fully specified (if not visible by default - in the same package or in java.lang)

• this doesn’t apply to wildcards which are always resolved in global scope

List has to be fully qualified, importing it into won’t help

@Pointcut("call(* java.util.List.*(..))")void listOperation() {}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 95

Annotation style development :Advice

• Annotation style advice is a method with the appropriate advice annotation• @Before @After @AfterReturning @AfterThrowing, @Around

before(Foo foo) : call(* org.pkg..*(..)) && this(foo) { System.out.println("Call from Foo: " + foo);}

@Before("call(* org.pkg..*(..)) && this(foo)")public void callFromFoo(Foo foo) { System.out.println("Call from Foo: " + foo);}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 96

summaryadvice before after around

inter-type decls Type.field Type.method()

declare error parents precedence

reflection thisJoinPoint thisJoinPointStaticPart

pointcuts -primitive- call execution handler get set initialization this target args within withincode cflow cflowbelow -user-defined- pointcut declaration abstract overriding

join points method & constructor call execution field get set exception handler execution initialization

aspects crosscutting type

© 2006 by Andy Clement, IBM: made available under the EPL v1.0

Part IIIAdopting AspectJ

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 98

when are aspects appropriate?

• Think! Is there a concern that:• crosscuts the structure of several objects or

operations• is beneficial to separate out

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 99

… crosscutting• a design concern that involves several

objects or operations• implemented without AOP would lead

to distant places in the code that• do the same thing

• e.g. traceEntry(“Point.set”)

• do a coordinated single thing• e.g. timing, observer pattern• harder to find these

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 100

… beneficial to separate out• exactly the same questions as for

objects• does it improve the code in real ways?

• separation of concerns• clarifies interactions, reduces tangling

• e.g. all the traceEntry are really the same• easier to modify / extend

• e.g. change the implementation of tracing• plug and play

• e.g. tracing aspects unplugged but not deleted

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 101

expected benefits of using AOP

• good modularity, even in the presence of crosscutting concerns• less tangled code, more natural code,

smaller code• easier maintenance and evolution

• easier to reason about, debug, change

• more reusable• more possibilities for plug and play• abstract aspects

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 102

Adopting AspectJreward

time & confidence

auxiliary /infrastructure

core /business

AO Analysis,AO Design,AO Strategy

explorationenforcement

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 103

Exploration & Enforcement• Aspects to monitor, analyze, debug system

• Can use individually or share with team

• Aspects that ensure design integrity• Can run privately, as part of nightly build, or shared w/

team

• Sharing with team can be supported by• integration in IDE or including in ant script

• No runtime dependency on AspectJ• production code has not been touched by AspectJ

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 104

Don’t use System.err.println !!!

public aspect EnforceLogging {

pointcut scope(): within(com.example..*) && !within(ConsoleDebugger);

pointcut printing(): get(* System.out) || get(* System.err) || call(* Throwable+.printStackTrace());

declare warning: scope() && printing(): "don't print, use the logger";}

• Warn developers using System.out, System.err and printStackTrace

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 105

Architectural Layering

View

Persistence

Model

Controller Layer 1

Layer 2

Layer 3

Layer 4

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 106

Map packages to components

aspect Architecture {

pointcut inView() : within(view..*); pointcut inModel() : within(model..*); pointcut inController() : within(controller..*); pointcut inPersistence() : within(persistence..*);

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 107

‘External’ calls into components

pointcut viewCall(): call(* view..*(..)) && !inView();

pointcut modelCall(): call(* model..*(..)) && !inModel();

pointcut controllerCall(): call(* controller..*(..)) && !inController();

pointcut persistenceCall(): call(* persistence..*(..)) && !inPersistence();

pointcut jdbcCall() : call(* javax.sql..*(..));

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 108

Compile warnings for illegal calls

… declare warning : controllerCall() : "No calls into controller";

declare warning : viewCall() && !inController() : "Only controller can call view";

declare warning : modelCall() && !(inController() || inView()) : "Only view and controller can call model";

declare warning : persistenceCall() && !inModel() : "Only model can access persistence layer";

declare warning : jdbcCall() && !inPersistence() : "Persistence layer handles all db access";

}

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 109

Auxiliary/Infrastructure

• Whole team awareness• developers know aspects are there• runtime dependency on aspectjrt.jar

• But only some developers • change working practices• change day-to-day tools

• Easily understood business case

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 110

Examples…• Tracing, logging• Error and exception handling• Monitoring and statistics gathering• Transactions• Session management (for e.g. persistence)• Threading• Synchronization• Caching• Remote access

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 111

Building the Case

• Factors:• Number of source files in project• Average time spent per file over a

release• (e.g. on tracing code) 100 files x 15 minutes = 25 person hours

500 files x 15 minutes = 3.5 person weeks

1000 files x 15 minutes = 7 person weeks

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 112

Building the Case

• You can certainly• write and test a simple tracing aspect in < 25

hours• write and test a good tracing aspect in < 50

hours• and save a lot of time 100 files x 15 minutes = 25 person hours

500 files x 15 minutes = 3.5 person weeks

1000 files x 15 minutes = 7 person weeks

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 113

Core/Business Aspects• Using aspects when implementing

application’s core functionality• Requires full team buy-in to AspectJ• Changes to tool set (e.g. JDT -> AJDT)• You’ll be ready if you followed staged approach

• enough developers will understand technology• enough developers will be aware of value• management will be aware of value

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 114

The books…

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 115

AspectJ on the web• AspectJ

• http://eclipse.org/aspectj

• AJDT• http://eclipse.org/ajdt

• Join the mailing lists from our homepage

• Email me! • Andy Clement, [email protected]

© 2006 by Andy Clement, IBM: made available under the EPL v1.0

Part IVHands on

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 117

Getting set up• Handouts and exercises plug-in:

• http://eclipse.org/ajdt/EclipseCon2006/

• Eclipse 3.1.1 or 3.1.2:• AJDT 1.3

• Eclipse 3.2RC2:• AJDT 1.4.dev

• AJDT downloads:• http://eclipse.org/ajdt/downloads/

• From the memory key:• Full eclipse including everything:

• Eclipse312_ajdt131_exercises.zip• Eclipse32rc2_ajdt140_exercises.jar

• Or… (unzip in your base eclipse directory)• Ajdt_1.3.1_for_eclipse_3.1.zip• Ajdt_1.4.0.20060503081550_archive.zip• AND• Org.aspectj.tutorial.exercises_1.0.0.jar

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 118

AspectJ technology• AspectJ is a small extension to Java

• valid Java programs are also valid AspectJ programs• AspectJ has its own compiler, ajc

• runs on Java 2 platform (Java 1.3 or later)• produces Java platform-compatible .class files

(Java 1.1 - 1.5)• AspectJ tools support

• Eclipse support: AJDT• ant tasks• works with existing debuggers

• license• compiler, runtime and tools are Open Source and free for

any use

© 2006 by Andy Clement, IBM: made available under the EPL v1.0 119

credits

AspectJ* & AJDT are Eclipse.org projectsCurrent AspectJ and AJDT committers:

Adrian Colyer, Matt Chapman, Andrew Clement, Helen Hawkins, Wes Isberg, Sian January, Mik Kersten, Alexandre Vasseur, Julie Waterhouse, and Matthew Webster

Notable work by: Ron Bodkin, Erik Hilsdale, Jim Hugunin, Gregor Kiczales

* Originally developed at PARC, with support from NIST and DARPA.

AspectJ is a registered trademark of Palo Alto Research Center Inc. in the United States and/or other countries.

Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.