Presentation is loading. Please wait.

Presentation is loading. Please wait.

Aspect-Oriented Programming w/AspectJ™ Cristina Lopes, Gregor Kiczales Xerox PARC © Copyright 1998, Xerox Corporation. All Rights Reserved. www.parc.xerox.com/aop.

Similar presentations


Presentation on theme: "Aspect-Oriented Programming w/AspectJ™ Cristina Lopes, Gregor Kiczales Xerox PARC © Copyright 1998, Xerox Corporation. All Rights Reserved. www.parc.xerox.com/aop."— Presentation transcript:

1 Aspect-Oriented Programming w/AspectJ™ Cristina Lopes, Gregor Kiczales Xerox PARC © Copyright 1998, Xerox Corporation. All Rights Reserved. www.parc.xerox.com/aop

2 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 3 an example system a distributed digital library

4 4 clean modular design title: string author: string isbn: int pdf: pdf tiff: tiff Library Book holds ** cooperates * * User accesses * * Printer uses **

5 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 UserLibrary 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; } } clean modular code

6 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 7 but... some issues don’t localize to objects –global coordination –interactions among many objects –resource sharing –error handling –performance optimizations –synchronization –...

8 8 Book Printer UserLibrary 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 Stringtitle; private Stringauthor; private Stringisbn; 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 9 Book Printer UserLibrary 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 Stringtitle; private Stringauthor; private Stringisbn; 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 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 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 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 Stringtitle; private Stringauthor; private Stringisbn; 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 13 aspect-oriented programming “aspects” are program constructs that cross-cut classes 1 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 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 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 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 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 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

19 Part II Basic Concepts of AspectJ

20 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 21 overview class instances code (methods) and some state state whereas the underlying Java™ language supports classes and objects

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

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

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

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

26 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 27 what it does Point p1 = new Point(); Point p2 = new Point(); p1 p2 The screen p1.set(3, 3); W W p2.setX(3);

28 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 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 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 31 Point p1 = new Point(); Point p2 = new Point(); p1 p2 The screen p1.set(3, 3); W W p2.setX(3); R int x = p1.getX(); extend to writes and reads...

32 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 ShowAccesses aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); } static before Point.getX, Point.getY,{ System.out.println(“R”); }

33 33 one aspect, two classes aspect ShowAccesses { static before Point.set, Point.setX, Point.setY { System.out.println(“W”); } Point ShowAccesses aspect 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 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 35 reads, writes and constructors 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”); } methods constructors

36 36 summary so far ShowAccesses Point one aspect, one class ShowAccesses Point one 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 37 aspects are special classes class 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 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 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 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 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 42 summary so far ShowAccesses Point n 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 n x m cross-cutting

43 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 44 simple use of aspect instances aspect 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 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 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); p3 a1.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 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 48 aspects compose Line ShowAccesses Point Circle LogNewInstancesAutoReset all three aspects apply to the class Point –more on controlling this in next part code retains good separation of concerns

49 49 here’s the complete code written with AspectJ with AspectJ 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 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 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 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 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 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

54 Part III Using AspectJ, the tool

55 55 source files Point ShowAccess “.ajava” files contain: regular Java source code aspect source code

56 56 processing aspects Point ShowAccess aspect weaver.ajava files byte code.class files

57 57 intermediate files Point ShowAccess aspect weaver.ajava files byte code.class files.java files Java code pre-processor: simplicity transition strategy

58 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 59 demo of the AspectJ tools

60 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 61 purpose and structure styles of aspects presented with examples: –common implementations –interaction (protocols) –shared state –specialized aspect libraries interleaved with more detail about AspectJ

62 62 notation Class object AspectInterface aspect instance slide containing semantic rules or conventions piece of implementation

63 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 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 65 outline using aspects to localize : –common implementations –interaction (protocols) –shared state specialized aspect libraries

66 66 example: plug & play tracing want to print out a trace message before and after every method of these classes; want to be able to turn it off class Customer { … } class Order { … } class Product { … }

67 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 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 69 special vars, scope rules specials: –thisAspect –thisObject –thisClassName –thisMethodName scope rules in body of weaves: 1. formals 2. aspect 3. object strings

70 70 an exception aspect XeroxServer Status getStatus() void registerClient(Client c) in all implementations of this interface, want to log exceptions

71 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 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 73 aspects for interfaces XeroxServerXeroxServerCatcher Class1Class2Class3... implements XeroxServerCatcher affects Class1, Class2, Class3,...

74 74 aspects that localize common code A B C A B C Aspect used in set-ups/clean-ups tracing logging method guards...

75 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 76 outline using aspects to localize : –common implementations –interaction (protocols) aspects as repositories of related implementations design patterns –shared state specialized aspect libraries

77 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 78 view of the update protocol Player TicTacToe public:... attach(TTTObserver) detach(TTTObserver) protected: notify() on state changes TTTObserver public: update() Canvas Label BoardDisplay update() StatusDisplay update() 6 tightly related methods and calls to notify() are spread all over

79 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 contains fields, methods and procedures of protocol

80 80 observer pattern Subject attach(Observer) detach(Observer) notify() on state changes Observer update() ConcreteObserver update() 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 81 observer pattern Observer update() ConcreteObserver update() implements Subject attach(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 82 observer pattern with aspects ConcreteObserver implements ConcreteSubject protocol implementation is encapsulated in the aspects Subject attach(Observer) detach(Observer) Observer update() SubjectObserver static new Observer.subject static new Subject.observers static new Subject.attach(Observer) static new Subject.detach(Observer) observers.addElement(obs); observers.removeElement(obs); ConcreteObserverUpdates static new ConcreteObserver.update() static after ConcreteSubject.m1, ConcreteSubject.m2,... for (int i = 0; i < observers.size(); i++) { obs = observers.elementAt(i); obs.update(); }

83 83 aspects that localize interaction A B C 1 23 4 A B C Aspect used in multi-class protocols – GUIs – notification –... many design patterns

84 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 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 86 static vs. non-static aspect 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 87 static vs. non-static fields aspect 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 88 static vs. non-static weaves two issues: 1. objects affected by weave 2. the existence of “thisAspect” related issue: the existence of “thisObject”

89 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 affects all Point objects, always Count2 count = new Count2(); count.addObject(p0); p0.set(3,3); non-static weave affects just the Point objects associated with an instance of Count2

90 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, this weave is executed without reference to a particular aspect instance may be omitted aspect Count2 { int count = 0; before Point.set, Point.setX, Point.setY { thisAspect.count++; } like a non-static method, this weave is executed with respect to particular aspect instance(s), thisAspect thisAspect available in non-static weaves

91 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 ) but a particular Point object, thisObject thisObject available in static and non-static weaves of non-static methods

92 92 static vs. non-static (specials) static weave non-static weave static method non-static method available: thisObject thisAspect thisClassName thisMethdName available: thisObject thisClassName thisMethodName available: thisClassName thisMethodName

93 93 special methods for aspects –void addObject(Object o) –void removeObject(Object o) –Vector getObjects() for objects –Vector getAspects()

94 94 example: a shared log file want to log new instances of these classes in one log file Customer Order Product

95 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) {} } globally shared by Customer, Order, Product

96 96 example: monitoring DBServer PrinterServer WebServer DocumentServer ServiceMonitoring

97 97 example: monitoring public 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 98 example: monitoring public 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 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 100 one monitor for all servers (static state) DBServer PrinterServer WebServer DocumentServer ServiceMonitoring static state static weaves only one incarnation of the static variables weaves statically associated with classes (they affect all objects)

101 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 102 service monitors 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’s state; sometimes sendCommand } static protected void sendCommand(Server srv, Command c) { srv.anOrder(c); }

103 103 monitors for groups of servers ServiceMonitoring DBServer PrinterServer WebServer DocumentServer state non-static weaves aServiceMonitor.addObject(aServer)

104 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 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 implementations of designated types Aspect subclass implements SuperType

106 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 107 the effective method { try { all befores all afters } all catches all finallys }

108 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 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 110 inheritance between aspects SuperAspect 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 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 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 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 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 OK OK

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

117 117 using an aspect aspect 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 out common code into a super

118 118 using coolib 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;}}); } 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 119 coolib avoid writing ad-hoc coordination code in the classes: use coordination aspects provide high-level constructs for programming coordination

120 120 coolib mutual exclusion coordination state conditional suspension/notification coordination actions

121 121 coolib Coordinator guardedEntry(String methName, boolean condition, CoordinationAction act) guardedExit(String methName, CoordinationAction act) addSelfex(String methName) addMutex(String[] methNames) some other variants of guardedEntry and guardedExit CoordinationAction doit() Condition checkit() included in distribution of AspectJ

122 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)

123 Part V Style Issues

124 124 outline when to use aspects –what existing knowledge tells us coding style issues –aspect/class interface –recursion

125 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 126 3 examples pull out access tracing pull out error handling pull out X and Y

127 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 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 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 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 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 have these 2 parts, but does it really make sense to separate them? where does set go? other methods that need x and y? do these 2 aspects improve the code?

132 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 good implementation of the point 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 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 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 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 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 137 one-to-one association trick obj asp SomeAspect 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

138 Part VI References, Related Work

139 139 AOP and AspectJ on the web http://www.parc.xerox.com/aop http://www.parc.xerox.com/aop/aspectj

140 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 141 AOP publications in proceedings of ECOOP’97 tech reports from PARC –http://www.parc.xerox.com/aop workshop papers –see workshop pages

142 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]


Download ppt "Aspect-Oriented Programming w/AspectJ™ Cristina Lopes, Gregor Kiczales Xerox PARC © Copyright 1998, Xerox Corporation. All Rights Reserved. www.parc.xerox.com/aop."

Similar presentations


Ads by Google