I. Overview of AOSD and AspectJ A. What is Aspect-Oriented Software Developement? 1. The problem, tangled code ------------------------------------------ THE PROBLEM CROSS-CUTTING CONCERNS AND TANGLING Some concerns cut across all modules: These have to be handled in many modules, resulting in tangled code ------------------------------------------ Other things like this? Why is it bad to handle this all over the code? 2. Why don't standard (OO) techniques solve the problem? a. watching changes (e.g., logging, tracing, ...) ------------------------------------------ AVOIDING THE PROBLEMS (1) Observer pattern: Every type (Subject) that does logging instead adds: - code for managing listeners - method, named "notify" to call listener's "actionPerformed" method when something should be logged - code to call notify when logging should happen But: ------------------------------------------ What problems would this cause? ------------------------------------------ WHAT'S NEEDED TO SUPPORT WATCHING CHANGES Want to: - avoid writing code in subjects to call notify (separate out decisions) - avoid writing code in observers to register listeners (separate out these decisions) - only pay at run-time when there are listeners ------------------------------------------ ------------------------------------------ JOIN POINTS In AspectJ, a *join point* is defined at every: - method call, constructor call - method/constructor body execution - initialization of an object - static initialization of a class - get of a field - set of a field - catch block handling an exception POINTCUTS In AspectJ, a *pointcut* is a set of join points. ------------------------------------------ What's the difference between a join point and a pointcut? ------------------------------------------ ADVICE In AspectJ, *advice* is code that is attached to a pointcut and can be run: - before - after each joinpoint in the pointcut. ------------------------------------------ ------------------------------------------ EXAMPLE (Kiselev listing 7.6) public aspect RigidLogger { pointcut logPoint() : execution(* tags.*.*(..)); before() : logPoint() { LogSys.log(thisJoinPoint); } } ------------------------------------------ b. assisting at run-time (caching, buffering, pooling, authentication, ...) ------------------------------------------ AVOIDING THE PROBLEMS (2) Changing performance by caching (or buffering, pooling, etc.): Instead of using raw type's object, use a proxy for it that: - contains an object of the raw type - delegates to it for basic functions - does the necessary caching, etc. by intercepting calls But: ------------------------------------------ ------------------------------------------ WHAT'S NEEDED TO SUPPORT ASSISTANCE Want to: - avoid writing the delegation code, especially when just passing along calls - avoid runtime overhead for delegation when not needed - avoid the use of decorators to deal with layers of proxies - avoid spreading concerns across multiple proxy types - avoid the need to change existing references to point to proxies ------------------------------------------ ------------------------------------------ AROUND ADVICE In AspectJ, *around advice* is advice that is run as follows: - it is called before a join point - it can decide to proceed (delegate) - when a proceed returns, the advice can perform more actions ------------------------------------------ ------------------------------------------ EXAMPLE (Kiselev, from listing 7.6) import java.sql.*; import java.util.*; public aspect ReadCache { public static Map cache = new Hashtable(); pointcut read(String user): call(Collection StoriesDb.retrieve(String)) && args(user); Collection around(String user) throws SQLException : read(user) { Collection res = (Collection)cache.get(user); if (null == res) { res = proceed(); cache.put(user, res); } return res; } } ------------------------------------------ What if multiple pieces of around advice apply at the same join point? 3. The promise ------------------------------------------ THE PROMISE OF AOSD Modular separation of concerns. Cross-cutting concerns confined to single modules. Systematic way to deal with non-functional requirements in design. Thus systems are: - easier to understand, - easier to change, adapt, evolve Can observe or change behavior without editing existing code. ------------------------------------------ What are the benefits of these benefits? 4. Typical Use ------------------------------------------ TYPICAL USES OF AOSD Uses of AOSD: - modularizing large programs (new code behaves as the old code) e.g., exception handling in telecom code - modularizing to add new behavior (superimpose new behavior on old code) e.g., add authentication to a program - support of product lines (new code is a variant in some aspects) e.g., add code to control new airplane - support performance improvements (treat special cases faster) e.g., bypass code for unused network layers ------------------------------------------ 5. Some problems and issues What is the programming methodology for finding crosscutting concerns? When is this a useful technique? Are there any privacy issues relating to join points? Are join points at the right level of abstraction? How can we understand code that uses aspects? II. Examples of AspectJ A. Basic tool use and join point model example 1. Command line tools ------------------------------------------ COMMAND LINE TOOLS $ cd joinpoints $ ajc *.java $ java Test ------------------------------------------ 2. Eclipse IDE ------------------------------------------ USING ECLIPSE $ eclipse ------------------------------------------ 3. playing with the example How would you enforce that the amount passed to credit must be non-negative? How would you enforce this for both credit and debit? B. tracing shape example 1. simple 2. reusable C. subject/observer example D. others III. AspectJ as a language A. Additions to Java Why is that reasonable? B. how AspectJ is (currently) implemented C. patterns 1. identifiers (method names, types) ------------------------------------------ IDENTIFIER (TYPE NAME) PATTERNS IdPattern ::= * | IdChars | IdPattern IdPattern | IdPattern .. IdPattern IdChars ::= IdChar | IdChars IdChar IdChar ::= a Java Identifier character | . SEMANTICS Matches: IdPattern, IdChars -> Boolean Matches(*, x) = x does not contain '.' Matches(i, x) = (x == i) and i in IdChars Matches(y z, x) = (\exists x1, x2 :: (x == x1+x2) and Matches(y,x1) and Matches(z,x2)) Matches(y .. z, x) = (\exists x1, x2, x3 :: (x == x1+x2+x3) and Matches(y,x1) and Matches(z,x3) and x2 is in IdChars and x2[0] == '.' and x2[x2.length()-1] == '.') Examples: Matches(get*X, getterX) Matches(org..Point, org.asj.Point) Matches(org..P*t, org.asj.Point) Matches(org..Point, org.Point) ------------------------------------------ ------------------------------------------ TYPE PATTERNS TypePattern ::= IdPattern | IdPattern + | TypePattern Arrays | ! TypePattern | TypePattern && TypePattern | TypePattern || TypePattern | ( TypePattern ) Arrays ::= [] | Arrays [] ------------------------------------------ How would you formalize the meaning of this? ------------------------------------------ SIGNATURE (METHOD AND CONSTRUCTOR) PATTERNS Signature ::= MethodPattern | ConstructorPattern MethodPattern ::= Modifiers TypePattern TypeDotOpt IdPattern ( TypePatternListOpt ) ThrowsOpt ConstructorPattern ::= Modifiers TypeDotOpt new ( TypePatternListOpt ) ThrowsOpt Modifiers ::= | Modifiers TypeDotOpt ::= | TypePattern . TypePatternListOpt ::= | TypePatternList TypePatternList ::= ListTypePattern | TypePatternList , ListTypePattern ListTypePattern ::= .. | TypePattern ThrowsOpt ::= | ThrowsPattern ThrowsPattern ::= ------------------------------------------ What should be the syntax of ThrowsPattern? What would be the semantics of these patterns? What kinds of patterns could we have in Smalltalk? Do we have dots (packages)? Types? Formals? D. pointcuts ------------------------------------------ POINTCUT SYNTAX PointCut ::= | call(Signature) | execution(Signature) | initialization(ConstructorPattern) | preinitialization(ConstructorPattern) | staticinitialization(TypePattern) | get(FieldPattern) | set(FieldPattern) | handler(TypePattern) | adviceexecution() | within(TypePattern) | withincode(Signature) | cflow(PointCut) | cflowbelow(PointCut) | if(Expression) | this(TypePatternOrVar) | target(TypePatternOrVar) | args(TypePatternOrVarList) | PointCut && PointCut | PointCut || PointCut | ! PointCut | Id(TypePatternOrVarList) TypePatternOrVar ::= TypePattern | Id TypePatternOrVarList ::= TypePatternOrVar | .. | TypePatternOrVarList , TypePatternOrVar | TypePatternOrVarList , .. ------------------------------------------ 1. call(Signature) 2. execution(Signature) 3. initialization(ConstructorPattern) How is this different than an execution join point for a constructor? How does this generalize to Smalltalk? 4. preinitialization(ConstructorPattern) 5. staticinitialization(TypePattern) How is this different than initialization? Does this make sense in Smalltalk? Is it needed? 6. get/set(FieldPattern) Does this make sense in Smalltalk? Is it needed? 7. handler(TypePattern) Does this make sense in Smalltalk? Is it needed? 8. adviceexecution() 9. within(TypePattern) ------------------------------------------ AVOIDING INFINITE LOOPS aspect A { before() : call(* *(..)) && !within(A) { System.out.println("before"); } after() returning : call(* *(..)) && !within(A) { System.out.println("after"); } } ------------------------------------------ 10. withincode(Signature) 11. cflow(PointCut) and cflowbelow(PointCut) a. cflow b. cflowbelow c. examples ------------------------------------------ CFLOW and CFLOWBELOW EXAMPLES From Kiselev Ch. 14: public class PtrnJPMain { public void test() { System.out.println( "*** Inside test ***"); } public static void main(String args[]) { System.out.println( "*** Calling test ***"); new PtrnJPMain().test(); } } public aspect PtrnJPSelected { pointcut begin() : execution(* *.main(..)); pointcut end() : execution(void PtrnJPMain.test()); pointcut p() : cflow(begin()) && !cflowbelow(end()); before() : p() && !within(PtrnJPSelected) { System.out.println(thisJoinPoint); } } ------------------------------------------ 12. if(Expression) What join points does if(true) match? 13. context join points a. this(TypePatternOrVar) b. target(TypePatternOrVar) c. args(TypePatternOrVarList) What if you have args(.., int, ..) and a join point is a call with 2 or more int arguments? 14. discussion How could we formalize the semantics of these? Which of these apply to Smalltalk? E. pointcut definitions ------------------------------------------ POINTCUT DECLARATIONS AspectMemberDecl ::= PointCutDeclaration | ... PointCutDeclaration ::= Modifiers pointcut Id(Formals); | Modifiers pointcut Id(Formals) : PointCut; Modifiers ::= | Modifiers Modifier Modifiers ::= abstract | public | ... E.g., abstract aspect AA { public abstract pointcut p(); public pointcut getCalls(Object o) : call(public * get(..)); } ------------------------------------------ What changes would be made in Smalltalk? F. advice ------------------------------------------ ADVICE SYNTAX AspectMemberDecl ::= PointCutDeclaration | AdviceDeclaration | ... AdviceDeclaration ::= StrictFPOpt AdviceType ThrowsListOpt : PointCut { Body } StrictFPOpt ::= | strictfp AdviceType ::= | before(Formals) | after(Formals) | after(Formals) returning ResultOpt | after(Formals) throwing ResultOpt | Type around(Formals) ResultOpt ::= | (Formal) ThrowsListOpt ::= | throws TypeList ------------------------------------------ ------------------------------------------ Examples of AdviceType: after (long x) returning after (long x) returning (long ret) after () throwing after () throwing (Exception e) int around(Stack s) throws Exception ------------------------------------------ What does "this" mean in the body of advice? What changes would be made in Smalltalk? How to explain the semantics of this? 1. special forms ------------------------------------------ SPECIAL FORMS IN ADVICE Expression ::= ... | thisJoinPoint | thisJoinPointStaticPart | thisEnclosingJoinPointStaticPart | proceed( Arguments ) ------------------------------------------ 2. syntactic sugars Can we translate before and after advice into around advice? 3. compilation semantics G. aspects ------------------------------------------ ASPECT SYNTAX Aspect ::= PrivilegedOpt Modifiers aspect Id ExtendsOpt ImplementsOpt PerClauseOpt { AspectBody } PrivilegedOpt ::= | privileged ExtendsOpts ::= | extends Type ImplementsOpts ::= | implements TypeList PerClauseOpts ::= | PerClause PerClause ::= pertarget (PointCut) | perthis (PointCut) | percflow (PointCut) | percflowbelow (PointCut) | issingleton AspectBody ::= | AspectBody AspectMemberDecl ------------------------------------------ When must an aspect be abstract? When can it? Can an aspect extend a Java class? Is that ok? How would this map to Smalltalk? IV. Other parts of AspectJ (static crosscutting) ------------------------------------------ OTHER USES OF ASPECTJ Provide: - glue code (joining existing programs) e.g., smooth over interface mismatches between two DBMS systems in a data warehouse program - enforce policies (laws) for software development e.g., never call service layer code directly, always go through facade ------------------------------------------ A. introductions 1. augmenting methods, and constructors, fields (static introductions) ------------------------------------------ AUGMENTING METHODS AND FIELDS (STATIC INTRODUCTIONS) AspectMemberDecl ::= ... | IntroductionDecl IntroductionDecl ::= | Modifiers Type Type.Id(Formals) ThrowsOpt { Body } | Modifiers Type TypePattern.Id(Formals) ThrowsOpt ; | Modifiers Type.new(Formals) ThrowsOpt { Body } | Modifiers Type Type.Id ; | Modifiers Type Type.Id = Expression ; E.g., import java.awt.Point; aspect AddLocation { private Point M.location = new Point(); public Point M.getLocation() { return location; } private M.setLocation(Point p) { location = p; } } ------------------------------------------ How would these be implemented? Why would you need these? What should "this" mean in a method used in one of these? How would these map to Smalltalk? If you can add all the methods needed for an interface, does that make a type implement that interface in Java? Can you add a private member to a type? What does that mean? How about a protected member? What happens if a private method is added to an interface, through some type pattern? Can you introduce constructors to an interface? Can you introduce a field in an interface? If you can introduce fields in an interface, do we get multiple inheritance of fields and all its problems? What happens if nothing matches the type pattern? 2. declare parents ------------------------------------------ DECLARE PARENTS AspectMemberDecl ::= ... | DeclareParentsDecl DeclareParentsDecl ::= | declare parents : TypePattern extends Type ; | declare parents : TypePattern implements TypeList ; E.g., aspect MakeCloneable { declare parents : mypack.* implements Cloneable; } aspect MakeRunnable { declare parents : MyType implements Runnable; public void MyType.run() { this.execute(); } } ------------------------------------------ What could this be used for? What happens if nothing matches the type pattern? What if a class matching the type pattern already has a superclass? What happens if the new interface demands methods that aren't implemented? 3. example 4. declare soft ------------------------------------------ DECLARE SOFT AspectMemberDecl ::= ... | DeclareSoftDecl DeclareSoftDecl ::= declare soft : Type : Pointcut ; e.g., from Kiselev's book: import java.io.*; import javax.servlet.jsp.tagext.*; public aspect Exceptions { declare soft : SQLException : call(* db.StoriesDb.*(..)); declare soft : IOException : call(* BodyContent.writeOut(..)); } ------------------------------------------ How would you simulate this using around advice? Would it make sense to use cflow in a pointcut for declare soft? B. static errors, declare error and warning ------------------------------------------ STATIC ERRORS AND WARNINGS AspectMemberDecl ::= ... | DeclareErrorDecl | DeclareWarningDecl DeclareErrorDecl ::= declare error : PointCut : String ; DeclareWarningDecl ::= declare warning : PointCut : String ; E.g., (from Kiselev's book): import java.sql.*; public aspect CodeSegregation { pointcut dbCode() : call(Connection DriverManager .getConnection(..)); pointcut badDbCode() : dbCode() && !within(db.*); pointcut reallyBadDbCode() : badDbCode() && !within(security.*) && !within(servlets.*); declare warning : badDbCode() : "Database code outside 'db' package."; declare error : reallyBadDbCode() : : "Database code is not permitted here."; } ------------------------------------------ What can these be used for? What restrictions on the pointcuts are necessary for this? C. declare precedence ------------------------------------------ DECLARE PRECEDENCE AspectMemberDecl ::= ... | DeclarePrecedenceDecl DeclarePrecedenceDecl ::= declare precedence : TypePatList ; e.g., declare precedence : Security, Logging, *; ------------------------------------------