Download presentation
Presentation is loading. Please wait.
Published byEugene Spencer Modified over 9 years ago
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]
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.