© 2006 by andy clement, ibm: made available under the epl v1.0 aspect-oriented programming with...
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 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 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 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 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.