370 likes | 375 Views
Explore the concept of Aspect-Oriented Programming and its application in program organization, separation of concerns, and handling crosscutting aspects. Includes examples and discussion on AspectJ and Adaptive Programming.
E N D
Lecture 21: Crosscutting Aspect-Oriented Programming "...feels like I've died and gone to Java Heaven." Don Asumu, Planning Tools Technical Development Leader, BT Laboratories on StructureBuilder, commercial tool based on Aspect-Oriented Programming, at http://www.webgain.com/Products/Structure_Builder/press_reviews.htm David Evans http://www.cs.virginia.edu/~evans CS655: Programming Languages University of Virginia Computer Science
Menu • Self-Application Answer • Sorting in Linda • Aspect-Oriented Programming “Separation of Concerns” • Examples • D (Distributed Language) • AspectJ • Adaptive Programming University of Virginia CS 655
Programming Paradigms • All the languages we have seen so far are “Generalized Procedure” languages: • Programs organized into procedures • Procedures may be grouped and associated with data • Some programs have properties (“aspects”) that cross-cut procedures • Examples: communication, synchronization, handling interrupts, security, loop fusion, etc. University of Virginia CS 655
Aspect-Oriented Programming Components (Functional Units) Aspect Weaver Procedural Program Aspects (Non-functional Units) Compiler Executable University of Virginia CS 655
Aspect Weaver Slide adapted from Gregor Kiczales ICSE Workshop Talk AO programming vs. idioms 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; } } class Book { private BookID id; private PostScript ps; private UserID borrower; public Book(String t, String a, String i, PostScript p) { id = new BookID(t,a,i); ps = p; } public UserID get_borrower() {return borrower;} public void set_borrower(UserID u) {borrower = u;} public PostScript get_ps() { return ps; } public BookID get_bid() { return id; } } class BookID { private String title; private String author; private String isbn; public BookID(String t, String a, String i) { title = t; author = a; isbn = i; } public String get_title() {return title;} } 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; } } public class PrinterImpl { String status = “Idle” Vector jobs; public PrinterImpl() {} pubilc get_status() { return status } public add_job(int j) { jobs.add(j); } } Classes 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 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; } } 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; } } 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; } } portal Library { Book find (String title){ return: Book: {copy title, author, isbn;} } } portal Printer { void print(Book book) { book: Book: {direct pages;} } Aspects class Book { private BookID id; private PostScript ps; private UserID borrower; public Book(String t, String a, String i, PostScript p) { id = new BookID(t,a,i); ps = p; } public UserID get_borrower() {return borrower;} public void set_borrower(UserID u) {borrower = u;} public PostScript get_ps() { return ps; } public BookID get_bid() { return id; } } class BookID { private String title; private String author; private String isbn; public BookID(String t, String a, String i) { title = t; author = a; isbn = i; } public String get_title() {return title;} } 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 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; } } 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; } } University of Virginia CS 655
Join Points • Aspects defined at “Join Points” • Typically, method invocations, entry and exits • Not limited to that – defined by aspect language • Aspect languages are domain specific • Define code or transformations to occur at join points University of Virginia CS 655
What is an aspect? • Definition 1: • A modular unit that has no stand-alone function • That is, it requires a context in order to function • And, that effects other modular units • Definition 2: • Something that implements properties that are not well-captured by functional units University of Virginia CS 655
D • Jcore – component language (Java subset, removed synchronization) • Cool – aspect language for expressing coordination of threads • Ridl – aspect language for expressing remote access strategies • Join Points – method invocations • Weaver just needs to put code at method entrances and exits • Can produce Java source code to compile normally University of Virginia CS 655
Cool • Define coordinators that specify locking semantics: • selfexclusive (method executed by at most one thread at a time) • mutexclusive (methods in same set cannot be executed concurrently) • Guarded suspension – define monitor-like abstractions separate from implementations • Can access, but not modify instance variables University of Virginia CS 655
Ties aspect to specific implementation! Cool Example coordinator BoundedStackCoord : BoundedStack { selfexclusive { pop, push }; mutexclusive { pop, push }; cond boolean full = false; cond boolean empty = true; push : requires !full; on_exit { empty = false; if (sp == MAX) full = true; } pop : requires !empty; on_exit { full = false; if (sp == 0) empty = true; } } } University of Virginia CS 655
Ridl • Control remote method invocations • Gives programmer control over copying semantics in parameter passing (can elect to copy just parts of object graph) remote Printer { Static print (Document: copy *.int, *.String, documentRepository)); ... } Only copy int and String fields, and reference to documentRepository. University of Virginia CS 655
AspectJ • crosscuts identify events • Can be associated with method calls, exception handlers • advice defines code associated with crosscuts University of Virginia CS 655
Tangled Example: Java API package java.io; public class File implements java.io.Serializable { private String path; ... public boolean exists() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } return exists0(); } public boolean canRead() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(path); } return canRead0(); } Exact same code, repeated 8 times in java.io.File • Why not make it a procedure? • Performance (method call overhead) • Better error messages (?) University of Virginia CS 655
Cross-cuts • crosscut name(context): event list crosscut fileReaders(java.io.File f): java.io.File & (boolean exists() | boolean canRead() | boolean canRead() | boolean isDirectory() | long lastModified() | long length() | String[] list() | String[] list(FilenameFilter filter)) • Wildcards crosscut nonStatics (): java.io.* & !static * (..); crosscut intMethods (): MyClass & public * (int); crosscut returnObject (): * & Object * (..); crosscut ioHandlers (): Account & * (..) & catch (IOException); University of Virginia CS 655
Advice • advice (Parameters) : crosscut advice checkRead (java.io.File f): fileReaders (f) { before { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead (path); } } } University of Virginia CS 655
AspectJ File Implementation • Aspects shown on previous slides • Simple implementation with security code removed package java.io; public class File implements java.io.Serializable { private String path; ... public boolean exists() { return exists0(); } public boolean canRead() { return canRead0(); } University of Virginia CS 655
Is AspectJ version better? • Advantages • Compact program • Separate concerns without any performance cost • Easier to change and reuse • Easier to understand and analyze policy • Disadvantages • Have to learn a new language • Extra compilation step • Debugging may be difficult (but special-purpose tools) University of Virginia CS 655
Example: Exception Handling • [Lippert & Lopes, 99] • Exception handling code clutters (and often dwarves) normal code • Tangled exceptions limit reuse • Cannot change exceptional behavior without overriding entire method • Tangled exceptions lose abstraction • All methods must handle network failures by retrying is scattered throughout code (and easy to forget) University of Virginia CS 655
JWAM Experiment • Java framework • Designed around design-by-contract with explicit calls to Contract.require and Contract.ensure • Use AspectJ to abstract out crosscut for contracts and exception handling • 11% of original code dealt with exception detection and handling; many handlers do the same thing University of Virginia CS 655
Bank Account public class Account { public Account (String owner, int accNo) { Contract.require (owner != null && owner.length() > 0); Contract.require (accNo > 0); this.owner = owner; this.accNo = accNo; } public void deposit (float amount) { Contract.require (amount > 0.0); balance += amount; } ... } University of Virginia CS 655
Aspect-Oriented Implementation class AccountContract { static advice Account & new(String s, int n) { before { Contract.require (s != null && s.length () > 0); Contract.require (n > 0); } } static advice Account & deposit (float f) { before { Contract.require (f > 0.0); } } } University of Virginia CS 655
Handling Library Exceptions • Typical code: try { registry.put (name, this); } catch (RemoteException e) { ErrorLog.print (“Remote call failed: ” + e); } • Replace with: crosscut remoteHandlers () : * & * *(..) & catch (RemoteException); static advice remoteHandlers () { catch (RemoteException e) { ErrorLog.print (“Remote call failed in ” + thisMethodName + “:” + e); } University of Virginia CS 655
Results • Reduced exception detection and handling code by a factor of 4.5 • Removed many simple conditions (null tests of results and arguments in contracts), common exception handlers • Is resulting code likely to be more reliable and maintainable? University of Virginia CS 655
Adaptive Programming: Demeter • Instance of AOP [Lieberherr92] • Aspects are traversal strategies • Separate the program text and the class structure • Program is independent of class graph • Accomplish tasks by traversals • Specification for what parts of received object should be traversed • Code fragments for what to execute when specific object types are encountered University of Virginia CS 655
Law of Demeter • Law of Demeter: a method should talk only to its friends: • arguments and part objects (computed or stored) • newly created objects • Dilemma: • Small method problem of OO (if followed) • Unmaintainable code (if not followed) • Traversal strategies are the solution to this dilemma • Demeter = Greek Goddess of Agriculture (grow software from small blocks) University of Virginia CS 655
Slide adapted from Karl Lieberherr talk AP Example: UML Class Diagram busStops BusRoute BusStopList buses 0..* BusStop BusList waiting 0..* passengers Bus PersonList Person 0..* AOP/Demeter
Slide adapted from Karl Lieberherr talk Collaborating Classes Find all persons waiting at any bus stop on a bus route busStops BusRoute BusStopList OO solution: one method for each red class buses 0..* BusStop BusList waiting 0..* passengers Bus PersonList Person 0..* AOP/Demeter
Java Solution (excerpt) class BusRoute { BusStopList busstops; void printWaitingPassengers () { busstops->printWaitingPassengers (); } } class BusStopList { BusStop stops[]; void printWaitingPassengers () { for (int i = 0; i < stops.length; i++) stops[i].printWaitingPassengers (); } } University of Virginia CS 655
Java Solution (cont.) class BusStop { PersonList waiting; void printWaitingPassengers () { waiting.print (); } } class PersonList { Person people[]; void print () { for (int i = 0; i < people.length; i++) people[i].print (); } } class Person { String name; void print () { System.stdout.println (name); } } University of Virginia CS 655
Demeter Approach • Devise a traversal strategy • Specify code for different types of objects reached on a traversal • Example: code prints name if object is a Person • Independent of class graph University of Virginia CS 655
Slide adapted from Karl Lieberherr talk Traversal Strategy First try:from BusRoute to Person busStops BusRoute BusStopList BusRoute BusStopList buses 0..* BusStop BusStop BusList BusList waiting 0..* passengers Bus PersonList Bus PersonList Person Person 0..* AOP/Demeter
Slide adapted from Karl Lieberherr talk Traversal Strategy from BusRoute through BusStop to Person busStops BusRoute BusStopList buses 0..* BusStop BusList waiting 0..* passengers Bus PersonList Person 0..* AOP/Demeter
Slide adapted from Karl Lieberherr talk Writing Adaptive Programs with Strategies strategy: from BusRoute through BusStop to Person BusRoute { traversalwaitingPersons(PersonVisitor) { through BusStop to Person; } // from is implicit void printWaitingPersons() // traversal/visitor weaving instr. = waitingPersons(PrintPersonVisitor); PrintPersonVisitor { before Person () < do printing >} AOP/Demeter
Slide adapted from Karl Lieberherr talk Robustness of Strategy from BusRoute bypassing Bus to Person villages BusRoute BusStopList buses VillageList busStops 0..* 0..* BusStop BusList Village waiting 0..* passengers Bus PersonList Person 0..* AOP/Demeter
Slide adapted from Karl Lieberherr talk Filter out noise in class diagram • only three out of seven classes • are mentioned in traversal • strategy! from BusRoute through BusStop to Person replaces traversal methods for the classes BusRoute VillageList Village BusStopList BusStop PersonList Person AOP/Demeter
Summary • Aspect-Oriented Programming and Adaptive Programming provide programmers with new expressive options • Active research area (Separation of Concerns Workshops at OOPSLA, ICSE, ECOOP, etc.) • Many directions to explore • Practical use still remains to be seen • Kiczales paper claims like OO in 1980 (by induction) • But some commercial success • Tendril Software (Adaptive programming tools for Java), bought by BEA Systems. http://www.webgain.com/Products/Structure_Builder/ University of Virginia CS 655
Charge • Next time: John Thornley • Project Progress • If your implementation will not be complete by Monday morning, schedule a meeting with me now University of Virginia CS 655