Aspect-Oriented Programming w/AspectJ™ Cristina Lopes, Gregor Kiczales Xerox PARC © Copyright...

Preview:

Citation preview

Aspect-Oriented Programming w/AspectJ™

Cristina Lopes, Gregor Kiczales

Xerox PARC

© Copyright 1998, Xerox Corporation. All Rights Reserved.

www.parc.xerox.com/aop

2

• using AOP and AspectJ to:– improve the design and source code modularity

of systems that involve cross-cutting concerns

• aspects are:– a new kind of programming construct, that

• supports a new kind of module• enables concerns that cross-cut the system to be

captured in clean units

• AspectJ is:– is an aspect-oriented extension to Java™ that

supports general-purpose aspect programming

this tutorial is about...

3

an example systema distributed digital library

4

clean modular design

title: stringauthor: stringisbn: intpdf: pdftiff: tiff

LibraryBookholds* *

cooperates**

User

accesses

*

*

Printeruses* *

5

public class PrinterImpl { String status = “Idle” Vector jobs;

public PrinterImpl() {} pubilc get_status() { return status } public add_job(int j) { jobs.add(j); }}

Book

Printer

User Libraryclass Library { Hashtable books; Library(){ books = new Hashtable(100); } public Book getBook(User u, String title) { System.out.println("REQUEST TO GET BOOK " + title); if(books.containsKey(title)) { Book b = (Book)books.get(title); System.out.println("getBook: Found it:" + b); if (b != null) { if (b.get_borrower() == null) b.set_borrower(u); return b; } } return null; }}

class User { private String name; Library theLibrary; Printer thePrinter;

public User(String n) { name = n; }

public boolean getBook (String title) { Book aBook = theLibrary.getBook(this, title); thePrinter.print(this,aBook); return true; }}

class Book { private String title; private String author; private String isbn; private PostScript ps; private User borrower;

public Book(String t, String a, String i, PostScript p) { title = t; author = a; isbn = i; ps = p; }

public User get_borrower() {return borrower;} public void set_borrower(User u) {borrower = u;} public PostScript get_ps() { return ps; }}

clean modular code

6

benefits of good modularity

• aka “clean separation of concerns”• each decision in a single place

– easy to understand– easy to modify– easy to unplug

7

but...

• some issues don’t localize to objects– global coordination– interactions among many objects– resource sharing– error handling– performance optimizations– synchronization– . . .

8

Book

Printer

User Libraryclass Book { private BookID id; private PostScript ps; private UserID borrower;

public Book(String t, String a, String i, PostScript p) { id = new BookID(t,a,i); ps = p; }

public UserID get_borrower() {return borrower;} public void set_borrower(UserID u) {borrower = u;} public PostScript get_ps() { return ps; } public BookID get_bid() { return id; }}

class BookID { private String title; private String author; private String isbn;

public BookID(String t, String a, String i) { title = t; author = a; isbn = i; } public String get_title() {return title;}}

class User { private UserID id; Library theLibrary; Printer thePrinter;

public User(String n) { id = new UserID(n); }

public boolean getBook (String title) { BookID aBook=null; try{ aBook = theLibrary.getBook(id, title); } catch (RemoteException e) {} try { thePrinter.print(id, aBook); } catch (RemoteException e) {} return true; } public UserID get_uid() { return id; }}

class UserID { private String name;

public UserID(String n) { name = n; } public String get_name() { return name; }}

interface LibraryInterface extends Remote { public BookID getBook(UserID u, String title) throws RemoteException;

public PostScript getBookPS(BookID bid) throws RemoteException;}

class Library extends UnicastRemoteObject implements LibraryInterface { Hashtable books; Library() throws RemoteException { books = new Hashtable(100); } public BookID getBook(UserID u, String title) throws RemoteException { System.out.println("REQUEST TO GET BOOK " + title); if(books.containsKey(title)) { Book b = (Book)books.get(title); System.out.println("getBook: Found it:" + b); if (b != null) { if (b.get_borrower() == null) b.set_borrower(u); return b.get_bid(); } } return null; } public PostScript getBookPS(BookID bid) throws RemoteException { if (books.containsKey(bid.get_title())) { Book b = (Book)books.get(bid.get_title()); if (b != null) return b.get_ps(); } return null; }

}

interface PrinterInterface extends Remote { public boolean print (UserID u, BookID b) throws RemoteException;}

public class Printer extends UnicastRemoteObject implements PrinterInterface { private Vector jobs = new Vector(10, 10); private Library theLibrary;

public Printer() throws RemoteException{} public boolean print (UserID u, BookID b) throws RemoteException{ PostScript ps=null; try{ ps = theLibrary.getBookPS(b); } catch (RemoteException e) {} Job newJob = new Job (ps, u); return queue(newJob); } boolean queue(Job j) { //... return true; }}

digital library with optimization

9

Book

Printer

User Libraryclass Book { private BookID id; private PostScript ps; private UserID borrower;

public Book(String t, String a, String i, PostScript p) { id = new BookID(t,a,i); ps = p; }

public UserID get_borrower() {return borrower;} public void set_borrower(UserID u) {borrower = u;} public PostScript get_ps() { return ps; } public BookID get_bid() { return id; }}

class BookID { private String title; private String author; private String isbn;

public BookID(String t, String a, String i) { title = t; author = a; isbn = i; } public String get_title() {return title;}}

class User { private UserID id; Library theLibrary; Printer thePrinter;

public User(String n) { id = new UserID(n); }

public boolean getBook (String title) { BookID aBook=null; try{ aBook = theLibrary.getBook(id, title); } catch (RemoteException e) {} try { thePrinter.print(id, aBook); } catch (RemoteException e) {} return true; } public UserID get_uid() { return id; }}

class UserID { private String name;

public UserID(String n) { name = n; } public String get_name() { return name; }}

interface LibraryInterface extends Remote { public BookID getBook(UserID u, String title) throws RemoteException;

public PostScript getBookPS(BookID bid) throws RemoteException;}

class Library extends UnicastRemoteObject implements LibraryInterface { Hashtable books; Library() throws RemoteException { books = new Hashtable(100); } public BookID getBook(UserID u, String title) throws RemoteException { System.out.println("REQUEST TO GET BOOK " + title); if(books.containsKey(title)) { Book b = (Book)books.get(title); System.out.println("getBook: Found it:" + b); if (b != null) { if (b.get_borrower() == null) b.set_borrower(u); return b.get_bid(); } } return null; } public PostScript getBookPS(BookID bid) throws RemoteException { if (books.containsKey(bid.get_title())) { Book b = (Book)books.get(bid.get_title()); if (b != null) return b.get_ps(); } return null; }

}

interface PrinterInterface extends Remote { public boolean print (UserID u, BookID b) throws RemoteException;}

public class Printer extends UnicastRemoteObject implements PrinterInterface { private Vector jobs = new Vector(10, 10); private Library theLibrary;

public Printer() throws RemoteException{} public boolean print (UserID u, BookID b) throws RemoteException{ PostScript ps=null; try{ ps = theLibrary.getBookPS(b); } catch (RemoteException e) {} Job newJob = new Job (ps, u); return queue(newJob); } boolean queue(Job j) { //... return true; }}

“cross-cutting”

this optimization cross-cuts the primary structure of the program

10

effects of cross-cutting

• “tangled code”• code duplication,• difficult to reason about

– why is this here?– what does this connect to?– difficult to make changes

• essentially, it destroys modularity

11

the AOP idea

• many cross-cuts aren’t random!– they serve specific purposes:

• performance optimizations, interactions among objects, enforcing consistency, tracking global state…

– they have well-defined structure:• lines of dataflow, boundary crossings, points

of resource utilization, points of access…

• so… let’s capture the cross-cutting structure in a modular way...

12

class User { private UserID id; Library theLibrary; Printer thePrinter;

public User(String n) { id = new UserID(n); }

public boolean getBook (String title) { BookID aBook=null; try{ aBook = theLibrary.getBook(id, title); } catch (RemoteException e) {} try { thePrinter.print(id, aBook); } catch (RemoteException e) {} return true; } public UserID get_uid() { return id; }}

class UserID { private String name;

public UserID(String n) { name = n; } public String get_name() { return name; }}

interface LibraryInterface extends Remote { public BookID getBook(UserID u, String title) throws RemoteException;

public PostScript getBookPS(BookID bid) throws RemoteException;}

class Library extends UnicastRemoteObject implements LibraryInterface { Hashtable books; Library() throws RemoteException { books = new Hashtable(100); } public BookID getBook(UserID u, String title) throws RemoteException { System.out.println("REQUEST TO GET BOOK " + title); if(books.containsKey(title)) { Book b = (Book)books.get(title); System.out.println("getBook: Found it:" + b); if (b != null) { if (b.get_borrower() == null) b.set_borrower(u); return b.get_bid(); } } return null; } public PostScript getBookPS(BookID bid) throws RemoteException { if (books.containsKey(bid.get_title())) { Book b = (Book)books.get(bid.get_title()); if (b != null) return b.get_ps(); } return null; }

}

interface PrinterInterface extends Remote { public boolean print (UserID u, BookID b) throws RemoteException;}

public class Printer extends UnicastRemoteObject implements PrinterInterface { private Vector jobs = new Vector(10, 10); private Library theLibrary;

public Printer() throws RemoteException{} public boolean print (UserID u, BookID b) throws RemoteException{ PostScript ps=null; try{ ps = theLibrary.getBookPS(b); } catch (RemoteException e) {} Job newJob = new Job (ps, u); return queue(newJob); } boolean queue(Job j) { //... return true; }}

class Book { private BookID id; private PostScript ps; private UserID borrower;

public Book(String t, String a, String i, PostScript p) { id = new BookID(t,a,i); ps = p; }

public UserID get_borrower() {return borrower;} public void set_borrower(UserID u) {borrower = u;} public PostScript get_ps() { return ps; } public BookID get_bid() { return id; }}

class BookID { private String title; private String author; private String isbn;

public BookID(String t, String a, String i) { title = t; author = a; isbn = i; } public String get_title() {return title;}}

public class PrinterImpl { String status = “Idle” Vector jobs;

public PrinterImpl() {} pubilc get_status() { return status } public add_job(int j) { jobs.add(j); }}

class Library { Hashtable books; Library(){ books = new Hashtable(100); } public Book getBook(User u, String title) { System.out.println("REQUEST TO GET BOOK " + title); if(books.containsKey(title)) { Book b = (Book)books.get(title); System.out.println("getBook: Found it:" + b); if (b != null) { if (b.get_borrower() == null) b.set_borrower(u); return b; } } return null; }}

class User { private String name; Library theLibrary; Printer thePrinter;

public User(String n) { name = n; }

public boolean getBook (String title) { Book aBook = theLibrary.getBook(this, title); thePrinter.print(this,aBook); return true; }}

class Book { private String title; private String author; private String isbn; private PostScript ps; private User borrower;

public Book(String t, String a, String i, PostScript p) { title = t; author = a; isbn = i; ps = p; }

public User get_borrower() {return borrower;} public void set_borrower(User u) {borrower = u;} public PostScript get_ps() { return ps; }}

portal Printer { void print(Book book) { book: Book: {direct pages;}

}portal Library { Book find (String title){ return: Book: {copy title, author, isbn;} }}

this aspect localizes the cross-cutting in one place

aspects: a cross-cutting module

13

aspect-oriented programming

• “aspects” are program constructs that cross-cut classes1 in well-defined, principled ways– the programmer uses classes to

implement the primary module structure– the programmer uses aspects to

implement the cross-cutting module structure

1 or other appropriate primary program construct, i.e. procedures if you added AOP to Scheme

14

aspect weaving

• weaver combines classes and aspects– compiler / pre-processor / interpreter– unambiguously coordinates cross-cutting

aspect weaver

public class PrinterImpl { String status = “Idle” Vector jobs;

public PrinterImpl() {} pubilc get_status() { return status } public add_job(int j) { jobs.add(j); }}

class Library { Hashtable books; Library(){ books = new Hashtable(100); } public Book getBook(User u, String title) { System.out.println("REQUEST TO GET BOOK " + title); if(books.containsKey(title)) { Book b = (Book)books.get(title); System.out.println("getBook: Found it:" + b); if (b != null) { if (b.get_borrower() == null) b.set_borrower(u); return b; } } return null; }}

class User { private String name; Library theLibrary; Printer the; Printer

public User(String n) { name = n; }

public boolean getBook (String title) { Book aBook = theLibrary.getBook(this, title); thePrinter.print(this,aBook); return true; }}

class Book { private String title; private String author; private String isbn; private PostScript ps; private User borrower;

public Book(String t, String a, String i, PostScript p) { title = t; author = a; isbn = i; ps = p; }

public User get_borrower() {return borrower;} public void set_borrower(User u) {borrower = u;} public PostScript get_ps() { return ps; }}

portal Printer { void print(Book book) { book: Book: {direct pages;}

}

portal Library { Book find (String title){ return: Book: {copy title, author, isbn;} }}

classes

aspects

executable code

15

benefits of using AOP

• good modularity, even in the presence of cross-cutting concerns– less tangled code, more natural code,

smaller code– easier maintenance and evolution

• easier to reason about, debug, change

– more reusable• plug and play

16

AspectJ™ is…

• the first general-purpose AO language– “lexical” cross-cutting (current)– concern-specific libraries (current)– other kinds of cross-cutting (future)

• an extension to Java• freely available implementation

– user community will drive future design

17

looking ahead

• AOP works because cross-cutting modularities aren’t random

• aspects are used to capture the structure of the cross-cutting in clean ways

AspectJ mechanisms Part II:

the kinds of cross-cutting mechanisms AspectJ can capture

problem structure Part IV:

how to use AspectJ to capture the higher-level cross-cutting in your systems

18

outline• I AOP overview

– motivation, what is the AOP idea

• II AspectJ overview– basic concepts, kinds of cross-cutting

• III key technical details– running the aspect weaver, source files, emacs support

• IV using AspectJ– more realistic examples, kinds of aspects, elaboration of

language semantics

• V style issues– when to use aspects, aspect coding style issues

• VI related work– survey of other activities in the AOP world

Part IIBasic Concepts of AspectJ

20

goals of this chapter

• present the basic concepts of AspectJ– the different kinds of cross-cutting– when aspect code runs– what context aspect code runs in

• using a single simple example

• the next chapters elaborate on– environment, tools– details of the semantics– what can be written using AspectJ

21

overview

class instances

code (methods)and some state

state

whereas the underlying Java™ language supports classes and objects

22

overview

class

aspect

AspectJ extends this with aspects that cross-cut the code in classes in various ways…

23

overview

class class

aspect

AspectJ extends this with aspects that cross-cut the code in classes in various ways…

24

overview

class class

aspect aspect

AspectJ extends this with aspects that cross-cut the code in classes in various ways…

25

overview

class class

aspect aspect

and aspect instances that cross-cut the state in objects in various ways

26

a first example

class Point { int _x = 0; int _y = 0;

void set (int x, int y) { _x = x; _y = y; }

void setX (int x) { _x = x; }

void setY (int y) { _y = y; }

int getX() { return _x; }

int getY() { return _y; }}

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); }}

27

what it does

Point p1 = new Point();Point p2 = new Point();

p1p2

The screen

p1.set(3, 3); W

Wp2.setX(3);

28

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); }}

Point

ShowAccesses

one aspect, one class

this “advise weave” affects several methods in the class

static: no aspect instances involved

before: do this before method body

29

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); }}

presentation note!

the syntax shown here is slightly simplified, mostly to save room on the slides

the full syntax for advise weaves on methods is presented in part iv

(also look at the SpaceWar code)

30

class Point { int _x = 0; int _y = 0;

void set (int x, int y) { System.out.println(“W”); _x = x; _y = y; } void setX (int x) { System.out.println(“W”); _x = x; } void setY (int y) { System.out.println(“W”); _y = y; } . .

here’s what we would have had to write in plain Java

without AspectJ

• what was in one place is instead in 3

• what was separated is now mixed in

31

Point p1 = new Point();Point p2 = new Point();

p1p2

The screen

p1.set(3, 3); W

Wp2.setX(3);

Rint x = p1.getX();

extend to writes and reads...

32

one aspect with two weaves

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); }}

Point

just as a class can have n methods

an aspect can have n weaves

ShowAccessesaspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); } static before Point.getX, Point.getY,{ System.out.println(“R”); }}

33

one aspect, two classes

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); }}

Point

ShowAccessesaspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); } static before Line.set, Line.setX1, ... { System.out.println(“W”); }}

Line

34

one aspect, two classes

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); }}

Point

ShowAccesses

Line

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY, Line.set, Line.setX1, ... { System.out.println(“W”); }}

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY, Line.set, Line.setX1, ... { System.out.println(“W”); } static before Point.getX, Point.getY, Line.getX1, ... { System.out.println(“R”); } }

35

reads, writes and constructorsaspect ShowAccesses { static before Point.set, Point.setX, Point.setY Line.set, Line.setX1, ... { System.out.println(“W”); } static before Point.getX, Point.getY, Line.getX1, ... { System.out.println(“R”); } static before Point(*), Line(*) { System.out.println(“C”); } }

methods

constructors

36

summary so far

ShowAccesses

Pointone aspect, one class

ShowAccesses

Pointone aspect, two classes

Line

static advise weaves allow aspect to:

• extend existing class definitions independent of any aspect instances

• by modifying existing methods/constructors

• nxm cross-cutting is coming up

37

aspects are special classesclass Point { … }

class Line { … }

class Circle { … }

aspect LogNewInstances { static DataOutputStream log = null; static { // initializer try { log = new DataOutputStream( new FileOutputStream(“log”)); } catch (IOException e) {} } static after Point(*), Line(*), Circle(*) { long time = System.currentTimeMillis(); try { log.writeBytes(“New instance at ” + time + “ ” + thisObject.toString() + “\n”); } catch (IOException e) {} }}

LogNewInstances

Point

Line

Circle

the objectaspect var

38

what it does

Point p1 = new Point(); p1

New instance at 3252384 Point321

p2

New instance at 3252451 Point322

Point p2 = new Point();

l1

New instance at 3252653 Line611

Line l1 = new Line();l2

New instance at 3255678 Line612

Line l2 = new Line();l3

New instance at 3258765 Line613

Line l3 = new Line();c1

New instance at 4532805 Circle901

Circle c1 = new Circle();

39

per-object aspect-related state

make Points go back to 0,0 after every 100 sets

Point

AutoReset

aspect AutoReset { static new int Point.count = 0; static after Point.set, Point.setX, Point.setY { if ( ++count >= 100 ) { count = 0; _x = 0; _y = 0; } }}

“new weaves” add definitions

• new fields, methods and constructors

• must be static

object’s scope

available

40

a peek ahead to style issues

make Points go back to 0,0 after every 100 sets

Point

AutoReset

aspect AutoReset { static new int Point.count = 0; static after Point.set, Point.setX, Point.setY { if ( ++count >= 100 ) { count = -1; set(0, 0); } }}

“new weaves” add definitions

• new fields, methods and constructors

• must be static

what is the class /

aspect inferace?

41

how this runs

count=0

Point p1 = new Point(); p1

count=0

Point p2 = new Point(); p2

p2.setY(7);

count=1

p1.set(3, 3);

count=1

p1.setX(3);

count=2

42

summary so farShowAccesses

Pointn aspects, m classes

Line

Point

AutoReset

adding state to each object

• advise weaves allow aspect to modify existing class definitions

• new weaves allow aspect to add to existing class definitions

• static means independent of any aspect instances

• nxm cross-cutting

43

aspect instances

Point

AutoReset

aspect can be instantiated and aspect instances can then be

associated with objects

as a first step, move the counter from objects to

aspect instances

44

simple use of aspect instancesaspect AutoReset { int count = 0; after Point.set, Point.setX, Point.setY { if (++count >= 100) { count = -1; set(0, 0); } }}

non-static

not a weave

45

what it does

Point p1 = new Point(); p1

Point p2 = new Point(); p2

AutoReset a1 = new AutoReset();

count=0

a1.addObject(p1);

count=0

AutoReset a2 = new AutoReset();

a2.addObject(p2);

p1.set(3, 3);

count=1

p1.setX(3);

count=2

p2.setY(7);

count=1

after instantiation of every Point object, instantiate an

AutoReset aspect and associate the two

46

one aspect instance, many objects

Point p1 = new Point(1, 1);

p1

Point p2 = new Point(1, 1);

p2

Point p3 = new Point(1, 1);

p3a1.addObject(p1);

a1.addObject(p3);

a1.addObject(p2);

the goal here is to get all of the Points to share a single AutoReset counter, so that they all reset, when as a group they have been set 100 times

AutoReset a1 = new AutoReset();

47

one aspect instance, many objects

aspect AutoReset { int count = 0; after Point.set, Point.setX, Point.setY { if (++count >= 100) { Vector objects = thisAspect.getObjects(); Enumeration e = objects.elements(); while (e.hasMoreElements()) { Point p = (Point)e.nextElement(); count = -1; p.set(0, 0); } } }}

aspect.getObjects() returns a vector of the objects

object.getAspects() returns a vector of the aspects

48

aspects compose

Line

ShowAccesses

Point Circle

LogNewInstances

AutoReset

• all three aspects apply to the class Point– more on controlling this in next part

• code retains good separation of concerns

49

here’s the complete code written with AspectJ

with AspectJclass Point { int _x = 0; int _y = 0;

void set (int x, int y) { _x = x; _y = y; }

void setX (int x) { _x = x; }

void setY (int y) { _y = y; }

int getX() { return _x; }

int getY() { return _y; }}

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY Line.set, Line.setX1, ... { System.out.println(“W”); } static before Point.getX, Point.getY, Line.getX1, ... { System.out.println(“R”); } static before Point(*), Line(*) { System.out.println(“C”); } }

aspect LogNewInstances { static DataOutputStream log = null; static { // initializer try { log = new DataOutputStream( new FileOutputStream(“log”)); } catch (IOException e) {} } static after Point(*), Line(*), Circle(*) { long time = System.currentTimeMillis(); try { log.writeBytes(“New instance at ” + time + “ ” + this.toString() + “\n”); } catch (IOException e) {} }}

aspect AutoReset { int counter = 0; after Point.set, Point.setX, Point.setY { if (++counter >= 100) { count = -1; set(0, 0); } }}

50

class Point { int _x = 0; int _y = 0;

Point () { System.out.println("C"); long time = System.currentTimeMillis(); try { log.writeBytes("New instance at " + time +

" " + Point.this.toString() + "\n"); } catch (IOException e) { } }

void set(int x, int y) { System.out.println("W"); _x = x; _y = y; doAutoResets(); }

void setX(int x) { System.out.println("W"); _x = x; doAutoResets(); }

void setY(int y) { System.out.println("W"); _y = y; doAutoResets();

}

int getX() { System.out.println("R"); return _x; }

int getY() { System.out.println("R"); return _y; }

here’s a well-written version of what we would have had to write in plain Java

without AspectJ

Vector autoResets = new Vector(); void doAutoResets() { java.util.Enumeration enumeration = autoResets.elements(); AutoReset reset; while (enumeration.hasMoreElements()) { reset = (AutoReset)enumeration.nextElement();

if(++ reset.count >= 100){ System.out.println("Reseting " + this + "."); reset.count = - 1; set(0,0);}

} }

static DataOutputStream log = null; static { try { log = new DataOutputStream(new FileOutputStream("log")); } catch (IOException e) { } } }

class AutoReset { int count = 0; public void addToScope(Point object) { object.autoResets.addElement(this); } public void removeFromScope(Point object) { object.autoResets.removeElement(this); } }

51

benefits of using AOP

• good modularity, even in the presence of cross-cutting concerns– less tangled code, more natural code,

smaller code– easier maintenance and evolution

• easier to reason about, debug, change

– more reusable• plug and play

52

summary

• advise weaves, new weaves• different kinds of cross-cutting

static and non-static• weave code runs in mixed scope

Line

ShowAccesses

PointCircle

LogNewInstances

AutoReset

53

looking ahead

• AOP works because cross-cutting modularities aren’t random

• aspects are used to capture the structure of the cross-cutting in clean ways

AspectJ mechanisms Part II: the low-level kinds of cross-

cutting AspectJ can capture

problem structure Part III: how to use AspectJ to capture

the higher-level kinds of cross-cutting in your systems

Part IIIUsing AspectJ, the tool

55

source files

Point

ShowAccess

“.ajava” files contain:

• regular Java source code• aspect source code

56

processing aspects

Point

ShowAccess

aspectweaver

.ajava files

bytecode

.classfiles

57

intermediate files

Point

ShowAccess

aspectweaver

.ajava files

bytecode

.classfiles

.javafiles

Javacode

pre-processor:• simplicity• transition strategy

58

programming environment

• source files– extension– contents

• look&feel of ajava mode for emacs– what aspects apply where

• weaving• woven code and tracking errors

59

demo of the AspectJ tools

Part IV - Using Aspects

AspectJ mechanisms Part II:

the kinds of cross-cutting mechanisms AspectJ can capture

problem structure Part IV:

how to use AspectJ to capture the higher-level cross-cutting in your systems

61

purpose and structure

• styles of aspects presented with examples:– common implementations

– interaction (protocols)

– shared state

– specialized aspect libraries

interleavedwithmore detailaboutAspectJ

62

notation

Class object

Aspect

Interface

aspectinstance

slide containingsemantic rulesor conventions

piece of implementation

63

terminology

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY Line.set, Line.setX1, ... { System.out.println(“W”); }}

designators

weave mode

weave declaration(“weave”, for short)

this syntax is slightly simplified, mostly to save room on the slides

see next slide for the full syntax for designators

64

designators

• methods: ResultType Type.Id ( Formals )

• constructors: Type ( Formals )

• initializers: Type

• fields: Type.Id

examples:

void Point.set(int x, int y) * Point.set(*) shapes.util.Point(*) Point(int x, int y) shapes.Point.x

methods

field

constructors

ResultType: Type | *Formals: TrueFormals | *

65

outline

• using aspects to localize :– common implementations– interaction (protocols)– shared state

• specialized aspect libraries

66

example: plug & play tracing

want to print out a trace message before and afterevery method of these classes;want to be able to turn it off

class Customer { … }

class Order { … }

class Product { … }

67

with an aspect

Customer

Order

Product

aspect Trace { static before * Customer.*(*), * Order.*(*), * Product.*(*) { System.out.println(“ENTERING ” + thisMethodID); }

static after * Customer.*(*), * Order.*(*), * Product.*(*) { System.out.println(“EXITING ” + thisMethodID); }

}

68

plug and play (plug and debug)

• plug in:

• plug out:

– turn debugging on/off without editing classes

– debugging disabled with no runtime cost– can save debugging code between uses

ajweaver Customer.ajava Order.ajava Product.ajava Trace.ajava

ajweaver Customer.ajava Order.ajava Product.ajava

69

special vars, scope rules

• specials:– thisAspect– thisObject– thisClassName– thisMethodName

• scope rules in body of weaves:1. formals2. aspect3. object

strings

70

an exception aspect

XeroxServer

Status getStatus()void registerClient(Client c)

in all implementationsof this interface, want to log exceptions

71

aspect XeroxServerCatcher {

static catch XeroxServer.getStatus, XeroxServer.registerClient (Exception e) { System.err.println(“Exception ” + e + “ at ” + System.currentTimeMillis()); throw e; }}

an exception aspect

type name

aspect XeroxServerCatcher {

static catch XeroxServer.getStatus, XeroxServer.registerClient (Exception e) { System.err.println(“Exception ” + e + “ at ” + System.currentTimeMillis()); throw e; }}

72

types

• in Java:– Interface = Type (no implementation)– Class = Type + implementation

• designators refer to types– aspects apply to interfaces too!

• weaves apply to all implementations

of the designated types

73

aspects for interfaces

XeroxServer XeroxServerCatcher

Class1 Class2 Class3 ...

implementsimplementsimplements

XeroxServerCatcher affectsClass1, Class2, Class3, ...

74

aspects that localize common code

A

B

C

A

B

C

Aspect

used in• set-ups/clean-ups• tracing• logging • method guards• ...

75

aspects that localize common code

• there is an abstraction occurring in several classes

• this abstraction can be implemented by a common piece of code

• inheritance is not best model or gets in the way of other code reuse

• aspect contains the common piece of code

76

outline

• using aspects to localize :– common implementations– interaction (protocols)

• aspects as repositories of related implementations

• design patterns

– shared state

• specialized aspect libraries

77

example: tic-tac-toe

Player

public: run() getTurn() endGame(Player, Result) actionPerformed(ActionEvent) mouseClicked(MouseEvent)protected: addStatusDisplay()

TicTacToe

public: run() startGame() newPlayer(Player) putMark(Player, Position) getBoard() getNPlayers() getCurrentPlayer() isOver() getResult() attach(TTTObserver) detach(TTTObserver)protected: waitForPlayers() waitForMove() endGame() notify() on state changes

TTTObserver

public: actionPerformed(ActionEvent) aboutWindow() update()protected: addMenu() addBoardDisplay() addStatusDisplay() finish()

2

TicTacToe

public: run() startGame() newPlayer(Player) putMark(Player, Position) getBoard() getNPlayers() getCurrentPlayer() isOver() getResult() attach(TTTObserver) detach(TTTObserver)protected: waitForPlayers() waitForMove() endGame() notify() on state changes

TTTObserver

public: actionPerformed(ActionEvent) aboutWindow() update()protected: addMenu() addBoardDisplay() addStatusDisplay() finish()

plus other classes...

78

view of the update protocol

Player

TicTacToe

public: ... attach(TTTObserver) detach(TTTObserver)protected: notify() on state changes

TTTObserver

public: update()

Canvas

Label

BoardDisplayupdate()

StatusDisplayupdate()

6 tightly relatedmethods andcalls to notify()are spread all over

79

the protocol in an aspect

TicTacToe

StatusDisplay

TTTObserver

BoardDisplay

aspect TTTDisplayProtocol { static new Vector TicTacToe.observers = new Vector(); static new Tictactoe TTTObserver.game;

static new void TicTacToe.attach(TTTObserver obs) { observers.addElement(obs); } static new void TicTacToe.detach(TTTObserver obs) { observers.removeElement(obs); } static new void TTTObserver.update() { board.update(game); status.update(game); } static new void BoardDisplay.update(TicTacToe game), StatusDisplay.update(TicTacToe game) { theGame = game; repaint(); } // all methods that change state static after TicTacToe.startGame, TicTacToe.newPlayer, TicTacToe.putMark, TicTacToe.endGame { for (int i = 0; i < observers.size(); i++) ((Observer)observers.elementAt(i)).update(); }}

aspect TTTDisplayProtocol { static new Vector TicTacToe.observers = new Vector(); static new Tictactoe TTTObserver.game;

static new void TicTacToe.attach(TTTObserver obs) { observers.addElement(obs); } static new void TicTacToe.detach(TTTObserver obs) { observers.removeElement(obs); } static new void TTTObserver.update() { board.update(game); status.update(game); } static new void BoardDisplay.update(TicTacToe game), StatusDisplay.update(TicTacToe game) { theGame = game; repaint(); } // all methods that change state static after TicTacToe.startGame, TicTacToe.newPlayer, TicTacToe.putMark, TicTacToe.endGame { for (int i = 0; i < observers.size(); i++) ((Observer)observers.elementAt(i)).update(); }}

aspect TTTDisplayProtocol { static new Vector TicTacToe.observers = new Vector(); static new Tictactoe TTTObserver.game;

static new void TicTacToe.attach(TTTObserver obs) { observers.addElement(obs); } static new void TicTacToe.detach(TTTObserver obs) { observers.removeElement(obs); } static new void TTTObserver.update() { board.update(game); status.update(game); } static new void BoardDisplay.update(TicTacToe game), StatusDisplay.update(TicTacToe game) { theGame = game; repaint(); } // all methods that change state static after TicTacToe.startGame, TicTacToe.newPlayer, TicTacToe.putMark, TicTacToe.endGame { for (int i = 0; i < observers.size(); i++) ((Observer)observers.elementAt(i)).update(); }}

aspect TTTDisplayProtocol { static new Vector TicTacToe.observers = new Vector(); static new Tictactoe TTTObserver.game;

static new void TicTacToe.attach(TTTObserver obs) { observers.addElement(obs); } static new void TicTacToe.detach(TTTObserver obs) { observers.removeElement(obs); } static new void TTTObserver.update() { board.update(game); status.update(game); } static new void BoardDisplay.update(TicTacToe game), StatusDisplay.update(TicTacToe game) { theGame = game; repaint(); } // all methods that change state static after TicTacToe.startGame, TicTacToe.newPlayer, TicTacToe.putMark, TicTacToe.endGame { for (int i = 0; i < observers.size(); i++) ((Observer)observers.elementAt(i)).update(); }}

aspect TTTDisplayProtocol { static new Vector TicTacToe.observers = new Vector(); static new Tictactoe TTTObserver.game;

static new void TicTacToe.attach(TTTObserver obs) { observers.addElement(obs); } static new void TicTacToe.detach(TTTObserver obs) { observers.removeElement(obs); } static new void TTTObserver.update() { board.update(game); status.update(game); } static new void BoardDisplay.update(TicTacToe game), StatusDisplay.update(TicTacToe game) { theGame = game; repaint(); } // all methods that change state static after TicTacToe.startGame, TicTacToe.newPlayer, TicTacToe.putMark, TicTacToe.endGame { for (int i = 0; i < observers.size(); i++) ((Observer)observers.elementAt(i)).update(); }}

aspect containsfields, methods and proceduresof protocol

80

observer pattern

Subject attach(Observer) detach(Observer) notify() on state changes

Observer update()

ConcreteObserverupdate()

ConcreteSubject

• protocol is spread in many classes• not so good in Java - uses up only inheritance link

With inheritance

observers.addElement(obs);

observers.removeElement(obs);

81

observer pattern

Observerupdate()

ConcreteObserverupdate()

implements

Subjectattach(Observer)detach(Observer)

implements

ConcreteSubject attach(Observer) detach(Observer)notify() on state changes

• protocol is spread in many classes• some replication of code in the concrete subjects

with interfaces

observers.addElement(obs);

observers.removeElement(obs);

82

observer patternwith aspects

ConcreteObserverimplements

implementsConcreteSubject

• protocol implementation is encapsulated in the aspects

Subjectattach(Observer)detach(Observer)

Observerupdate()

SubjectObserverstatic new Observer.subjectstatic new Subject.observersstatic new Subject.attach(Observer)static new Subject.detach(Observer)

observers.addElement(obs);

observers.removeElement(obs);

ConcreteObserverUpdatesstatic new ConcreteObserver.update()static after ConcreteSubject.m1, ConcreteSubject.m2, ...

for (int i = 0; i < observers.size(); i++) { obs = observers.elementAt(i); obs.update();}

83

aspects that localize interaction

A

B

C

1

2 3

4 A

B

C

Aspect

used in• multi-class protocols

– GUIs– notification– ...

• many design patterns

84

aspects that localize interaction

• there is an interaction (protocol) involving several classes

• methods of the protocol are more coupled with each other than with the classes where they “sit”

• aspect captures the whole protocol

85

outline

• using aspects to localize :– common implementations– interaction (protocols)– shared state

• static vs non-static state• when to use aspect instances

• specialized aspect libraries

86

static vs. non-staticaspect Count1 { static int count = 0; static before Point.set, Point.setX, Point.setY { count++; }}

aspect Count2 { int count = 0; before Point.set, Point.setX, Point.setY { thisAspect.count++; }}

class Point { int _x = 0; int _y = 0;

void set (int x, int y) { _x = x; _y = y; }

void setX (int x) { _x = x; }

void setY (int y) { _y = y; }

int getX() { return _x; }

int getY() { return _y; }}

87

static vs. non-static fieldsaspect Count1 { static int count = 0; static before Point.set, Point.setX, Point.setY { count++; }}

one incarnation of count (same as static in class fields)

one incarnation of count per aspect instance(same as non-static in class fields)

Point p0 = new Point(0,0);Point p1 = new Point(1,1);

aspect Count2 { int count = 0; before Point.set, Point.setX, Point.setY { thisAspect.count++; }}

Point p0 = new Point(0,0);Point p1 = new Point(1,1);

88

static vs. non-static weaves

two issues:

1. objects affected by weave2. the existence of “thisAspect”

related issue: the existence of “thisObject”

89

static vs. non-static weaves (1)

aspect Count2 { int count = 0; before Point.set, Point.setX, Point.setY { thisAspect.count++; }}

Point p0 = new Point(0,0);Point p1 = new Point(1,1);p0.set(3,3); p1.set(4,4);

aspect Count1 { static int count = 0; static before Point.set, Point.setX, Point.setY { count++; }}

Point p0 = new Point(0,0);Point p1 = new Point(1,1);p0.set(3,3); p1.set(4,4);

static weave affectsall Point objects, always

Count2 count = new Count2();count.addObject(p0);p0.set(3,3);

non-static weave affects justthe Point objects associated with an instance of Count2

90

static vs. non-static weaves (2)aspect Count1 { static int count = 0; static before Point.set, Point.setX, Point.setY { count++; }}

like a static method, thisweave is executed withoutreference to a particularaspect instance

may be omitted

aspect Count2 { int count = 0; before Point.set, Point.setX, Point.setY { thisAspect.count++; }}

like a non-static method, thisweave is executed withrespect to particularaspect instance(s), thisAspect

thisAspect available in non-static weaves

91

static vs. non-static (methods)aspect Count1 { static int count = 0; static before Point.set, Point.setX, Point.setY { count++; }}

class Point { int _x = 0; int _y = 0;

void set (int x, int y) { _x = x; _y = y; } void setX (int x) { _x = x; } void setY (int y) { _y = y; } int getX() { return _x; } int getY() { return _y; }}

non-static methods

no particular aspect instance(no thisAspect)buta particular Point object, thisObject

thisObject available in static and non-static weaves of non-static methods

92

static vs. non-static (specials)

static weave

non-static weave

static method

non-staticmethod

available: thisObject thisAspect thisClassName thisMethdName

available: thisObject thisClassName thisMethodName

available: thisClassName thisMethodName

93

special methods

• for aspects– void addObject(Object o)– void removeObject(Object o)– Vector getObjects()

• for objects– Vector getAspects()

94

example: a shared log file

want to log new instances of these classes in one log fileCustomer

Order

Product

95

static aspect state

Customer

Order

Product

aspect LogNewInstances { static DataOutputStream log = null; static { // initializer try { log = new DataOutputStream( new FileOutputStream(“log”)); } catch (IOException e) {} } static after Customer(*), Order(*), Product(*) { long time = System.currentTimeMillis(); try { log.writeBytes(“New instance at ” + time + “ ” + thisObject.toString() + “\n”); } catch (IOException e) {} }}

globallyshared byCustomer,Order,Product

96

example: monitoring

DBServer

PrinterServer

WebServer

DocumentServer

ServiceMonitoring

97

example: monitoringpublic class DBServer { public Result query(Query q) { monitor.anEvent(new SEvent(this)); try { return processQuery(q); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally { monitor.anEvent(new OKEvent(this)); }

} public Status getStatus() { monitor.anEvent(new IEvent(this)); return status;

} ...}

public class PrinterServer { public void print(Path p) { monitor.anEvent(new SEvent(this)); try { printit(p); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} public Status getStatus() { monitor.anEvent(new IEvent(this)); return status;

} ...}

public class WebServer { public void post(Data d) { monitor.anEvent(new SEvent(this)); try { postit(d); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} public Data get(Path p) { monitor.anEvent(new SEvent(this)); try { return getit(p); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} ...}

public class DocumentServer { public Doc convert(Doc d,Format f) { monitor.anEvent(new SEvent(this)); try { return convertData(d, f); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} public void newDocument(Doc d) { monitor.anEvent(new SEvent(this)); try { addDocument(d); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} ...}

98

example: monitoringpublic class DBServer { public Result query(Query q) { monitor.anEvent(new SEvent(this)); try { return processQuery(q); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally { monitor.anEvent(new OKEvent(this)); }

} public Status getStatus() { monitor.anEvent(new IEvent(this)); return status;

} ...}

public class PrinterServer { public void print(Path p) { monitor.anEvent(new SEvent(this)); try { printit(p); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} public Status getStatus() { monitor.anEvent(new IEvent(this)); return status;

} ...}

public class WebServer { public void post(Data d) { monitor.anEvent(new SEvent(this)); try { postit(d); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} public Data get(Path p) { monitor.anEvent(new SEvent(this)); try { return getit(p); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} ...}

public class DocumentServer { public Doc convert(Doc d,Format f) { monitor.anEvent(new SEvent(this)); try { return convertData(d, f); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} public void newDocument(Doc d) { monitor.anEvent(new SEvent(this)); try { addDocument(d); } catch (Exception e) { monitor.anEvent(new XEvent(this)); } finally {monitor.anEvent(new OKEvent(this));}

} ...}

monitor.anEvent(new SEvent(this));try { return processQuery(q); }catch (Exception e) { monitor.anEvent(new XEvent(this));} finally { monitor.anEvent(new OKEvent(this));}

99

aspect as monitor (static state)

aspect ServiceMonitoring { static Vector serversInfo = new Vector(5); static int totalServiceRequests, totalExceptions, totalCompletions;

static before DBServer.query, WebServer.post, WebServer.get, PrinterServer.print, DocumentServer.convert, DocumentServer.newDocument { anEvent(new SEvent(thisObject)); } more befores, afters, catches, finally

static void anEvent(Event e) { update aspect state; sometimes sendCommand } static protected void sendCommand(Server srv, Command c) { srv.anOrder(c); }}

100

one monitor for all servers (static state)

DBServer

PrinterServer

WebServer

DocumentServer

ServiceMonitoringstatic state

staticweaves

• only one incarnation of the static variables

• weaves statically associated with classes (they affect all objects)

101

the need for aspect instances

• need different instances of aspect state – e.g. different monitors for different

groups of servers

• need a handle for the aspect state– e.g. remote service monitor

102

service monitorsaspect ServiceMonitoring { static Vector serversInfo = new Vector(5); static int totalServiceRequests, totalExceptions, totalCompletions;

static before DBServer.query, WebServer.post, WebServer.get, PrinterServer.print, DocumentServer.convert, DocumentServer.newDocument { anEvent(new SEvent(thisObject)); } more befores, afters, catches, finally

static void anEvent(Event e) { update aspect’s state; sometimes sendCommand } static protected void sendCommand(Server srv, Command c) { srv.anOrder(c); }}

103

monitors for groups of servers

ServiceMonitoring

DBServer

PrinterServer

WebServer

DocumentServer

state

state

non-staticweaves

aServiceMonitor.addObject(aServer)

104

inheritance of aspects

class MyDocumentServer extends DocumentServer {

protected boolean checkConsistency() { ... }

public Doc convert(Doc d, Format f) { Doc newDoc = super.convert(d, f); if (checkConsistency(newDoc)) return newDoc; else return null; }

}

override

extension

105

inheritance of aspects

SuperClass

SubClass

Aspect

extends

overriding of methods in sub: • aspect still applies and • doesn’t repeat in calls to super

SuperType applies to all implementationsof designated types

Aspect subclass implementsSuperType

106

inheritance of aspects

A foo()

B foo()

extends

Aspect1 before A.foo {...}

what code runs in•(new A()).foo() ? Aspect1’s before, A.foo

•(new B()).foo() ? Aspect1’s before, Aspect2’s before, B.foo

• if B.foo calls super.foo() ? same as previous; Aspect1’s before does not repeat

Aspect2 before B.foo {...}

107

the effective method

{ try { all befores < call to method containing original body > all afters } all catches all finallys}

108

aspect as monitor (static state)

aspect ServiceMonitoring { static Vector serversInfo = new Vector(5); static int totalServiceRequests, totalExceptions, totalCompletions;

static before DBServer.query, WebServer.post, WebServer.get, PrinterServer.print, DocumentServer.convert, DocumentServer.newDocument { anEvent(new SEvent(thisObject)); } more befores, afters, catches, finally

static void anEvent(Event e) { update aspect state; sometimes sendCommand } static protected void sendCommand(Server srv, Command c) { srv.anOrder(c); }}

109

inheritance between aspects

aspect VerboseMonitor extends ServiceMonitoring { ObjectOutputStream logStream;

VerboseMonitor() { initialize logStream }

protected void log(Event e) { logStream.writeObject(e); }

public void anEvent(Event e) { System.out.println(e.toString()); log(e); super.anEvent(e); }

}

override

extension

110

inheritance between aspectsSuperAspect

SubAspect

extends• similar to inheritance between classes:– subaspect inherits methods, fields

and weaves of superaspect– subaspect can extend superaspect

with new methods, fields and weaves– subaspect can override methods and

fields of superaspect (for now)

111

aspects that localize shared state

A

B

C

O

A

B

C

Aspect

used in• multi-class protocols with state

– authentication– monitoring– object management– ...

• encapsulation of state relating to groups of objects

112

aspects that localize shared state

• state needs to be encapsulated• an object / a class would do, but• interactions that affect the state of

such object are well localized

• aspect contains that state and the weaves for interaction

113

outline

• using aspects to localize :– common implementations– interaction (protocols)– shared state

• specialized aspect libraries– cross-cutting abstractions– code-intensive, repetitive actions

(goal of all libraries)

114

the cross-cutting nature of concurrency control

Problem: a square and a circle are manipulated by several concurrent threads. They can both change color. However, they can’t both be red at the same time; a changeColor(red) request on one of them must wait if the other is currently red.

Not OKOK

115

cross-cutting is unavoidable

the cross-cutting nature of concurrency control

class Square extends Shape { Pos pos; int size; Color color; fields for coordination

public void changeColor(Color c){ some coordination code here color = c; some coordination code here } …}

class Circle extends Shape { Pos pos; int r; Color color; fields for coordination

public void changeColor(Color c){ some coordination code here color = c; some coordination code here } …}

code may be more or less encapsulated, but

116

aspect NoSimultaneousRed { Shape redShape = null; // holds the reference to // the red shape or null

before void Square.changeColor(Color color), void Circle.changeColor(Color color) { if (color == Color.red) { synchronized (thisAspect) { while (!(redShape == null || redShape == thisObject)) { try { wait(); } catch (InterruptedException e) {} } redShape = thisObject; } }

} after void Square.changeColor(Color color), void Circle.changeColor(Color color) { if (color != Color.red) { synchronized (thisAspect) { if (thisObject == redShape) // coming out of red redShape = null; notifyAll(); } }

}}

using an aspectaspect NoSimultaneousRed { Shape redShape = null; // holds the reference to // the red shape or null

before void Square.changeColor(Color color), void Circle.changeColor(Color color) { if (color == Color.red) { synchronized (thisAspect) { while (!(redShape == null || redShape == thisObject)) { try { wait(); } catch (InterruptedException e) {} } redShape = thisObject; } }

} after void Square.changeColor(Color color), void Circle.changeColor(Color color) { if (color != Color.red) { synchronized (thisAspect) { if (thisObject == redShape) // coming out of red redShape = null; notifyAll(); } }

}}

117

using an aspectaspect NoSimultaneousBlue { Shape blueShape = null; // holds the reference to // the blue shape or null

before void Square.changeColor(Color color), void Circle.changeColor(Color color) { if (color == Color.blue) { synchronized (thisAspect) { while (!(blueShape == null || blueShape == thisObject)) { try { wait(); } catch (InterruptedException e) {} } blueShape = thisObject; } }

} after void Square.changeColor(Color color), void Circle.changeColor(Color color) { if (color != Color.blue) { synchronized (thisAspect) { if (thisObject == blueShape) // coming out of blue blueShape = null; notifyAll(); } }

}}

can pull outcommoncodeinto asuper

118

using coolibaspect NoSimultaneousRed extends Coordinator { Shape redShape = null; before void Square.changeColor(String color), void Circle.changeColor(String color) { if (color == Color.red) guardedEntry(thisMethodID, new Condition() { boolean checkit() { return (redShape == null || redShape == thisObject);}}, new CoordinationAction() { void doit() { redShape = thisObject; } });

} after void Square.changeColor(String color), void Circle.changeColor(String color) { if (color != Color.red) guardedExit(thisMethodID, new CoordinationAction() { void doit() {if (thisObject==redShape) redShape = null;}});

}}

aspect NoSimultaneousRed extends Coordinator { Shape redShape = null; before void Square.changeColor(String color), void Circle.changeColor(String color) { if (color == Color.red) guardedEntry(thisMethodID, new Condition() { boolean checkit() { return (redShape == null || redShape == thisObject);}}, new CoordinationAction() { void doit() { redShape = thisObject; } });

} after void Square.changeColor(String color), void Circle.changeColor(String color) { if (color != Color.red) guardedExit(thisMethodID, new CoordinationAction() { void doit() {if (thisObject==redShape) redShape = null;}});

}}

119

coolib

• avoid writing ad-hoc coordination code in the classes: use coordination aspects

• provide high-level constructs for programming coordination

120

coolib

• mutual exclusion• coordination state• conditional suspension/notification• coordination actions

121

coolib

Coordinator

guardedEntry(String methName, boolean condition, CoordinationAction act)guardedExit(String methName, CoordinationAction act)addSelfex(String methName)addMutex(String[] methNames)

some other variants ofguardedEntry and guardedExit

CoordinationAction

doit()

Condition

checkit()

included in distribution of AspectJ

122

summary• aspects capture design abstractions

that involve several classes• many different flavors of aspects

– common implementations– protocols– state plus protocol

• aspects build on existing practices and techniques for OO– instantiation, inheritance– libraries for programming aspects

(e.g. coolib)

Part VStyle Issues

124

outline

• when to use aspects– what existing knowledge tells us

• coding style issues– aspect/class interface– recursion

125

good designs

• capture “the story” well• may lead to good

implementations, measured by– code size– tangling– coupling– etc.

learned through experience,

influenced by taste and style

126

3 examples

• pull out access tracing • pull out error handling• pull out X and Y

127

a good aspect (access tracing)class Point { ... void set (int x, int y) {...} void setX (int x) { ... } void setY (int y) { ... } int getX() { ... } int getY() { ... }}

aspect ShowAccesses { static before Point.set, Point.setX, Point.setY, Line.set, Line.setX1, Line.setY1, Line.setX2, Line.setY2 { System.out.println(“W”); }}

“access tracing” is a good abstraction on its own

class Line { ... void set(int x1,int y1, int x2,int y2) {...} void setX1 (Point p) {...} void setY1 (Point p) {...} void setX2 (Point p) {...} void setY2 (Point p) {...}}

128

a good aspect (access tracing)class Point { int _x = 0; int _y = 0;

void set (int x, int y) { System.out.println(“W”); _x = x; _y = y;

} void setX (int x) { System.out.println(“W”); _x = x;

} void setY (int y) { System.out.println(“W”); _y = y;

} int getX() { return _x;

} int getY() { return _y;

}}

alternative implementation:

• more tangled

• redundant information

• commonality is lost

• consistent change is harder

• harder to unplug

harder to maintain

129

a good aspect (errors)class DocumentServer { Doc convert(Doc d,Format f){ search locally and remotely } DocID lookupDoc (…) { search locally and remotely } void storeDoc (…) { store locally, notify remotely } void scanDoc (…) { get document from scanner }}

aspect DocumentServerErrors { static catch (RemoteException e) DocumentServer.lookupDoc, DocumentServer.storeDoc { pop up message offering to change the default server } static catch (DeviceError e) DocumentServer.convert, DocumentServer.scanDoc { pop up message offering to call the key operator }}

“how to deal with errors in the document server” is a good abstraction on its own

130

a good aspect (errors)class DocumentServer { Doc convert(Doc d,Format f){ try { search locally and remotely } catch (DeviceError e) { pop up message offering to call the key operator } } DocID lookupDoc (…) { try { search locally and remotely } catch (RemoteException e) { pop up message offering to change the default server } } void storeDoc (…) { try { store locally, notify remotely } catch (RemoteException e) { pop up message offering to change the default server } } ...

alternative implementation:

• more tangled

• redundant information

• commonality is lost

• consistent change is harder

• harder to unplug

harder to maintain

even single-class aspects can help, if they separate out some reasonable design concern

131

two questionable aspects

class Point {}

aspect XPart { static new Point._x = 0; static new int Point.getX() { return _x; } static new void Point.setX(int x) { _x = x; }}aspect YPart { static new int Point._y = 0; static new int Point.getY() { return _y; } static new void Point.setY(int y) { _y = y; }}

points havethese 2 parts,butdoes it reallymake sense toseparate them?

where does set go? other methods that need x and y?

do these 2 aspects improve the code?

132

two questionable aspects

class Point { int _x = 0; int _y = 0; void setX (int x) { _x = x; } void setY (int y) { _y = y; } int getX() { return x; } int getY() { return y; } void set (int x, int y) { _x = x; _y = y; }}

the Point class is a goodimplementation of thepoint abstraction:

• no redundant information• no lost commonalties• no tangling• no difference in size• plug in/out: what’s a point without the X part?

not really

do these 2 aspects improve the code?

133

when to use aspects

• is there a concern that:– cross-cuts the structure of several

classes or methods– is beneficial to separate out

134

… cross-cutting

• a design concern that involves several classes or methods

• implemented without AOP would lead to distant places in the code that– do the same thing

• (i.e. println(“W”), logging)• try grep to find these [Griswald]

– do a coordinated single thing• (i.e. observer pattern, synchronization)• harder to find these

135

… beneficial to separate out

does it improve the code in real ways?– separation of concerns

• think about service without logging

– clarifies interactions, reduces tangling• all the log.writeBytes are really the same• checking that the “other object” isn’t red

– easier to modify / extend• change “W” to “a variable was set”• aspect frameworks

– plug and play• can turn off aspect easily• debugging aspects unplugged but not deleted

136

benefits of using AOP

• good modularity, even in the presence of cross-cutting concerns– less tangled code, more natural code,

smaller code– easier maintenance and evolution

• easier to reason about, debug, change

– more reusable• plug and play

137

one-to-one association trick

obj

aspSomeAspect asp = new SomeAspect();SomeClass obj = new SomeClass();asp.addObject(obj);

aspect SomeAspect { static after SomeClass(*) { SomeAspect asp = new SomeAspect(); asp.addObject(thisObject); } ...}

SomeClass obj = new SomeClass();// aspect instance is associated with obj

make aspect know about class more than the other way

Part VIReferences, Related Work

139

AOP and AspectJ on the web

• http://www.parc.xerox.com/aop

• http://www.parc.xerox.com/aop/aspectj

140

workshops

• ECOOP’97– http://wwwtrese.cs.utwente.nl/aop-ecoop97

• ICSE’98– http://www.parc.xerox.com/aop/icse98

• ECOOP’98– http://wwwtrese.cs.utwente.nl/aop-ecoop98

141

AOP publications

• in proceedings of ECOOP’97• tech reports from PARC

– http://www.parc.xerox.com/aop

• workshop papers– see workshop pages

142

work we know best

• subject-oriented programming @ IBM

– [Ossher, Harrison]

• adaptive programming @ Northeastern U

– [Lieberherr]

• composition filters @ U Twente

– [Aksit]

• assessment of SE techniques @ UBC– [Murphy]

• information transparency @ UCSD– [Griswald]

Recommended