Lecture 21: Crosscutting Aspect- Oriented Programming

advertisement
Lecture 21: Crosscutting AspectOriented 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
CS655: Programming Languages
David Evans
University of Virginia
http://www.cs.virginia.edu/~evans
Computer Science
Menu
• Self-Application Answer
• Sorting in Linda
• Aspect-Oriented Programming
“Separation of Concerns”
• Examples
– D (Distributed Language)
– AspectJ
– Adaptive Programming
27 July 2016
University of Virginia CS 655
2
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.
27 July 2016
University of Virginia CS 655
3
Aspect-Oriented Programming
Components
(Functional Units)
Aspect
Weaver
Procedural
Program
Aspects
(Non-functional Units)
Compiler
Executable
27 July 2016
University of Virginia CS 655
4
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 class PrinterImpl {
String status = “Idle”
public Book(String t, String a, String i, PostScript p) { Vector jobs;
title = t;
public PrinterImpl() {}
author = a;
pubilc get_status() { return status }
isbn = i;
public add_job(int j) {
ps = p;
jobs.add(j);
}
}
}
public User get_borrower() {return borrower;}
public void set_borrower(User u) {borrower = u;}
public PostScript get_ps() { return ps; }
class
User {
}
class Library {
private String name;
Hashtable books;
Library theLibrary;
Library(){
Printer the; Printer
books = new Hashtable(100);
}
public User(String n) { name = n; }
public Book getBook(User u, String title) {
System.out.println("REQUEST TO GET BOOK " + title);
public boolean getBook (String title) {
if(books.containsKey(title)) {
Book aBook = theLibrary.getBook(this, title);
Book b = (Book)books.get(title);
thePrinter.print(this,aBook);
System.out.println("getBook: Found it:" + b);
return true;
if (b != null) {
}
if (b.get_borrower() == null)
}
b.set_borrower(u);
return b;
}
}
return null;
}
portal Library
{
portal Printer {
}
Book find
(String title){
void print(Book book) {
return:
book: Book: {direct pages;}
Book: {copy title, author,
isbn;}
}
}
}
class Book {
private BookID
id;
private PostScript ps;
private UserID
borrower;
class User {
private UserID id;
Library theLibrary;
Printer thePrinter;
public Book(String t, String a,
String i, PostScript p) {
id = new BookID(t,a,i);
ps = p;
}
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; }
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; }
Classes
}
class BookID {
private String title;
private String author;
private String isbn;
Aspect
Weaver
public BookID(String t, String a, String i) {
title = t;
author = a;
isbn = i;
}
public String get_title() {return title;}
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;
}
interface LibraryInterface extends Remote {
public BookID getBook(UserID u, String title) throws RemoteException;
public PostScript getBookPS(BookID bid) 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;
}
Aspects
}
}
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;
}
{
}
class Book {
private BookID
id;
private PostScript ps;
private UserID
borrower;
class User {
private UserID id;
Library theLibrary;
Printer thePrinter;
public Book(String t, String a,
String i, PostScript p) {
id = new BookID(t,a,i);
ps = p;
}
public User(String n) { id = new UserID(n); }
public boolean getBook (String title) {
BookID aBook=null;
try{
aBook = theLibrary.getBook(id, title);
UserID get_borrower() {return borrower;}
} catch (RemoteException e) {}
void set_borrower(UserID u) {borrower = u;} try {
PostScript get_ps() { return ps; }
thePrinter.print(id, aBook);
BookID get_bid() { return id; }
} catch (RemoteException e) {}
}
return true;
}
class BookID {
public UserID get_uid() { return id; }
private String title;
}
private String author;
private String isbn;
class UserID {
private String name;
public BookID(String t, String a, String i) {
interface PrinterInterface extends Remote {
interface LibraryInterface extends Remote {
title = t;
public UserID(String n) { name = n; }
public boolean print (UserID u, BookID b)
public BookID getBook(UserID u, String title) throws RemoteException;
author = a;
public String get_name() { return name; }
throws RemoteException;
isbn = i;
}
}
public PostScript getBookPS(BookID bid) throws RemoteException;
}
}
public String get_title() {return title;}
public class Printer extends UnicastRemoteObject
}
implements PrinterInterface class
{
Library extends UnicastRemoteObject implements LibraryInterface {
private Vector jobs = new Vector(10, 10);
Hashtable books;
private Library theLibrary;
Library() throws RemoteException {
books = new Hashtable(100);
public Printer() throws RemoteException{}
}
public boolean print (UserID u, BookID b)
public BookID getBook(UserID u, String title)
throws RemoteException{
throws RemoteException {
PostScript ps=null;
System.out.println("REQUEST TO GET BOOK " + title);
try{
if(books.containsKey(title)) {
ps = theLibrary.getBookPS(b);
Book b = (Book)books.get(title);
} catch (RemoteException e) {}
System.out.println("getBook: Found it:" + b);
Job newJob = new Job (ps, u);
if (b != null) {
return queue(newJob);
if (b.get_borrower() == null)
}
b.set_borrower(u);
boolean queue(Job j) {
return b.get_bid();
//...
}
return true;
}
}
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;
}
public
public
public
public
27 July 2016
University of Virginia CS 655
5
}
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
27 July 2016
University of Virginia CS 655
6
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
27 July 2016
University of Virginia CS 655
7
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
27 July 2016
University of Virginia CS 655
8
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
27 July 2016
University of Virginia CS 655
9
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; }
}
}
Ties aspect to specific implementation!
27 July 2016
University of Virginia CS 655
10
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.
27 July 2016
University of Virginia CS 655
11
AspectJ
• crosscuts identify events
– Can be associated with method calls,
exception handlers
• advice defines code associated with
crosscuts
27 July 2016
University of Virginia CS 655
12
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 (?)
27 July 2016
University of Virginia CS 655
13
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);
27 July 2016
University of Virginia CS 655
14
Advice
• advice (Parameters) : crosscut
advice checkRead (java.io.File f): fileReaders (f) {
before {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead (path);
}
}
}
27 July 2016
University of Virginia CS 655
15
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(); }
27 July 2016
University of Virginia CS 655
16
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)
27 July 2016
University of Virginia CS 655
17
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)
27 July 2016
University of Virginia CS 655
18
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
27 July 2016
University of Virginia CS 655
19
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;
}
...
}
27 July 2016
University of Virginia CS 655
20
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); } }
}
27 July 2016
University of Virginia CS 655
21
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); }
27 July 2016
University of Virginia CS 655
22
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?
27 July 2016
University of Virginia CS 655
23
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
27 July 2016
University of Virginia CS 655
24
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)
27 July 2016
University of Virginia CS 655
25
Slide adapted from Karl Lieberherr talk
AP Example: UML Class Diagram
busStops
BusRoute
BusStopList
buses
0..*
BusStop
BusList
0..*
waiting
passengers
Bus
PersonList
Person
7/27/2016
AOP/Demeter
0..*
26
Slide adapted from Karl Lieberherr talk
Collaborating Classes
Find all persons waiting at any bus stop on a bus route
busStops
BusRoute
buses
BusList
0..*
BusStopList
OO solution:
one method
for each red
class
BusStop
waiting
passengers
Bus
PersonList
Person
7/27/2016
0..*
AOP/Demeter
0..*
27
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 ();
}
}
27 July 2016
University of Virginia CS 655
28
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); } }
27 July 2016
University of Virginia CS 655
29
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
27 July 2016
University of Virginia CS 655
30
Slide adapted from Karl Lieberherr talk
Traversal Strategy
First try: from BusRoute to Person
busStops
BusRoute
BusStopList
buses
0..*
BusStop
BusList
0..*
waiting
passengers
Bus
PersonList
Person
7/27/2016
AOP/Demeter
0..*
31
Slide adapted from Karl Lieberherr talk
Traversal Strategy
from BusRoute through BusStop to Person
busStops
BusRoute
BusStopList
buses
0..*
BusStop
BusList
0..*
waiting
passengers
Bus
PersonList
Person
7/27/2016
AOP/Demeter
0..*
32
Slide adapted from Karl Lieberherr talk
Writing Adaptive Programs with
Strategies
strategy: from BusRoute through BusStop to Person
BusRoute {
traversal waitingPersons(PersonVisitor) {
through BusStop to Person; } // from is implicit
void printWaitingPersons() // traversal/visitor weaving instr.
= waitingPersons(PrintPersonVisitor);
PrintPersonVisitor {
before Person () < do printing >}
7/27/2016
AOP/Demeter
33
Slide adapted from Karl Lieberherr talk
Robustness of Strategy
from BusRoute bypassing Bus to Person
BusRoute
buses
BusList
0..*
villages
VillageList
0..*
Village
busStops
0..*
BusStop
waiting
passengers
Bus
PersonList
Person
7/27/2016
BusStopList
AOP/Demeter
0..*
34
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
7/27/2016
AOP/Demeter
35
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/
27 July 2016
University of Virginia CS 655
36
Charge
• Next time: John Thornley
• Project Progress
– If your implementation will not be complete
by Monday morning, schedule a meeting
with me now
27 July 2016
University of Virginia CS 655
37
Download