670 likes | 819 Views
Adaptive Aspect-Oriented Programming in AspectJ. Karl J. Lieberherr Northeastern University Joint work of Demeter Research Group. Overview. What is “adaptive programming”? Examples in AspectJ. What is behind adaptiveness in AspectJ? Why we need more adaptiveness in AspectJ.
E N D
Adaptive Aspect-Oriented Programming in AspectJ Karl J. Lieberherr Northeastern University Joint work of Demeter Research Group UCI Feb 03
Overview • What is “adaptive programming”? • Examples in AspectJ. What is behind adaptiveness in AspectJ? • Why we need more adaptiveness in AspectJ. • DAJ: a simple adaptive add-on to AspectJ. • Abstraction behind “more adaptiveness” • LoD in AspectJ (adapts to any Java program) • Conclusions UCI Feb 03
Adaptive? • A program is adaptive if it changes its behavior according to its context. • Adaptive programs: Concurrency policy, Distribution policy, Logging Aspect, Adaptive Method, Law of Demeter Checker in AspectJ • Possible contexts • Java program or its execution tree • UML class diagram or object diagram UCI Feb 03
What is the role of adaptive features in AOP • They become increasingly more important as AOP is applied to larger problems. • Encapsulating an aspect without abstracting over the relevant join points leads to brittle code. • AspectJ has many adaptive features but more is needed. UCI Feb 03
AspectJ team slide Adaptive Aspects abstractpublicaspect RemoteExceptionLogging { abstractpointcut logPoint(); after() throwing(RemoteException e): logPoint() { log.println(“Remote call failed in: ” + thisJoinPoint.toString() + “(” + e + “).”); } } abstract publicaspect MyRMILogging extends RemoteExceptionLogging { pointcut logPoint(): call(* RegistryServer.*.*(..)) || call(private * RMIMessageBrokerImpl.*.*(..)); } UCI Feb 03
A Different Kind of Adaptive Aspect AspectJ team slide abstract aspect CapabilityChecking { pointcut invocations(Caller c): this(c) && call(void Service.doService(String)); pointcut workPoints(Worker w): target(w) && call(void Worker.doTask(Task)); pointcut perCallerWork(Caller c, Worker w): cflow(invocations(c)) && workPoints(w); before (Caller c, Worker w): perCallerWork(c, w) { w.checkCapabilities(c); } } UCI Feb 03
A more complex adaptive aspect:Law of Demeter Checker (Object Form) aspect Check { … after(): Any.MethodCall{ // call (* *(..)); // check whether // thisJoinPoint.getTarget() // is a preferred supplier // object } UCI Feb 03
Observation 1 • Many AspectJ programs are adaptive (designed for a family of Java programs) • Context: Java program or its execution tree (lexical joinpoints or dynamic join points) • Features enabling adaptiveness: • *, .. (wildcards) • cflow, + (graph transitivity) • this(s), target(s), args(a), call (…), … (inheritance as wild card) • pc(Object s, Object t): this(s) && target(t) && call(… f …) UCI Feb 03
Observation 2 • Want to improve the adaptive capabilities of AspectJ: AspectJ still leads to tangling and duplication. UCI Feb 03
Overview • What is “adaptive programming”? • Examples in AspectJ. What is behind adaptiveness in AspectJ? • Why we need more adaptiveness in AspectJ. • DAJ: a simple adaptive add-on to AspectJ. • Abstraction behind “more adaptiveness” • LoD in AspectJ • Conclusions UCI Feb 03
Listing files in a FileSystem f root :FileName :FileSystem :CompoundFile contents first :File_PList :NonEmpty_File_PList next it :CompoundFile parent f contents UCI Feb 03
public aspect FileSystemTraversals { public void CompoundFile.listAll() { FileLister v = new FileLister(); eachFile(v); void CompoundFile.eachFile(…) { … if (contents != null) eachFile_crossing_contents(newTokens); } void CompoundFile. eachFile_crossing_contents(…) { this.contents.eachFile(tokens); } // much more } UCI Feb 03
Example of an Adaptive Method in AspectJ (DAJ) aspect FileSystemTraversals { declare traversal: void listAll(): "from CompoundFile to File" (FileLister); } UCI Feb 03
http://daj.sourceforge.net/ • DAJ gives you • the power of AspectJ and • the beauty of DJ and • the convenience of DemeterJ • all at once without having to learn a new programming language other than AspectJ and a schema notation (Java Data Binding) . UCI Feb 03
Another Adaptive Method aspect FileSystemTraversals { declare strategy: eachFile: "intersect(from CompoundFile to File, down)"; declare traversal: void listAll(): eachFile(FileLister); declare strategy: down: "from * bypassing -> *,parent,* to *"; } UCI Feb 03
High-level AspectJ advice using dynamic join points! What To Do class FileLister { Stack path = new Stack(); void before(File file) { path.push(file.name);} void after(File file) { System.out.print(" ."); Iterator it = path.iterator(); it.next(); while (it.hasNext()) System.out.print("/" + it.next()); System.out.println(); path.pop();} } UCI Feb 03
Ordinary Java Class class Main { public static void main(String[] args) { FileSystem fs = FileSystem.parse(new File(args[0])); Commands script = Commands.parse(new File(args[1])); script.interpret(fs.root); System.out.println(" Status of File System "); fs.root.listAll(); } } UCI Feb 03
Domain-specific aspect languages • What is a good infrastructure for this? • Goes back to the theme of Crista: domain-specific aspect languages. UCI Feb 03
DAJ • What is new for the AspectJ programmer • Two additional declarations • declare strategy: including intersection • declare traversal • Object structure and language aspect • class dictionary files UCI Feb 03
range of AOP languages means of … join points JPM join points identifying specifying semantics at AspectJ dynamic JPM points in execution call, get, set… signaturesw/ wildcards & other properties of JPs advice static JPM class members signatures add members DemeterJ, DAJ dynamic JPM static JPM 1 static JPM 2 static JPM 3 when traversal reaches object or edge class members class members class members visitor method signatures traversal spec. s class graph g class names class graph visitor method bodies s + g (result = traversal implementation) add members class graph with tokens=grammar (result = parsing and printing implementation) UCI Feb 03
Overview • What is “adaptive programming”? • Examples in AspectJ. What is behind adaptiveness in AspectJ? • Why we need more adaptiveness in AspectJ. • DAJ: a simple adaptive add-on to AspectJ. • Abstraction behind “more adaptiveness” • LoD in AspectJ • Conclusions UCI Feb 03
A General Graph-based Adaptive Mechanism • Three layers of graphs: Bottom, Middle,Top • Bottom layer: trees to select subtrees guided by top layer. Each bottom layer tree has a graph from the • Middle layer associated with it that contains meta-information about the bottom layer tree. Acts as an abstraction barrier between the top and bottom layers. Used to reduce search space. • Top layer graph is basically a subgraph of the transitive closure of the middle layer graph, decorated with additional information attached to the edges. UCI Feb 03
Top graph: subgraph of transitive closure of middle layer B A C Middle graph: Abstraction barrier B A C Bottom tree: select subtrees B c1:C c2:C c3:C A UCI Feb 03
Graph-based adaptiveness • The call graph application (AspectJ): • Top: computational pattern, • Middle: static call graph, • Bottom: call tree. • The standard application (Demeter): • Top: strategy graph, • Middle: class graph, • Bottom: object trees. UCI Feb 03
Call graph example jp_lock = call(R.lock()) jp_write = call(R.write()) jp_unlock = call(R.unlock()) jp_read = call(R.read()) jps1 = from jp_start to {jp_lock, jp_write, jp_unlock, jp_read} jps2 = from jp_start bypassing {jp_lock, jp_write, jp_unlock, jp_read} to {jp_lock, jp_write, jp_unlock, jp_read} jps1 = jps2. UCI Feb 03
Overview • What is “adaptive programming”? • Examples in AspectJ. What is behind adaptiveness in AspectJ? • Why we need more adaptiveness in AspectJ. • DAJ: a simple adaptive add-on to AspectJ. • Abstraction behind “more adaptiveness” • LoD in AspectJ • Conclusions UCI Feb 03
Aspects and lexical join points • Going to the roots of the Northeastern branch of AOP: Law of Demeter. • Closing the circle: Write an ultimately adaptive program in AspectJ: • Works with all Java programs • Checks the object-form of the Law of Demeter: “talk only to your friends” UCI Feb 03
Instrumentation of Java programs with Aspects Aspect framework Aspect Diagram Supplier ImmediatePartBin TargetBinStack ArgumentBin Checker LocallyConstructedBin uses pointcuts ReturnValueBin Requirements: Statistics GlobalPreferredBin Good Separation of Concerns in Law of Demeter Checker UCI Feb 03
Explanation • The *bin* aspects collect potential preferred supplier objects that represent good coupling in the context of a method body. • The Checker aspect checks each method call whether the receiver is a preferred supplier object. • The Statistics aspect counts events generated by the Checker aspect. UCI Feb 03
Law of Demeter(Join Point Form) JPT(ID) = [<target> ID] <args> List(ID) <children> List(JPT) [<ret> ID]. List(S) ~ {S}. UCI Feb 03
JPT(ID) = [<target> ID] <args> List(ID) <children> List(JPT) [<ret> ID]. List(S) ~ {S}. E target t2 args {a1,a2} target t2 ret r1 J r1.foo1() a1.bar() t2.foo2() r3.foo2() target null ret r3 UCI Feb 03
Generic Law of Demeter(Join Point Form) Definition 1: The LoD_JPF requires that for each join point J, target(J) is a potential preferred supplier of J. Definition 2: The set of potential preferred suppliers to a join point J, child to the enclosing join point E, is the union of the objects in the following sets: UCI Feb 03
Generic Law of Demeter(Join Point Form) • Argument rule: the args of the enclosing join point E, including the target • Associated rule: the associated values of E: the ret values of the children of E before J whose target is the target of E or whose target is null. UCI Feb 03
aspect LoD extends Violation { pointcut LoD_JPF(): //LoD definition ArgumentRule() || AssociatedRule(); pointcut ArgumentRule(): if(thisEnclosingJoinPoint.getArgs() .contains(thisJoinPoint.getTarget()); pointcut AssociatedRule(): if(thisEnclosingJoinPoint .hasSelfishChild(thisJoinPoint .getTarget())); } UCI Feb 03
Pseudo Aspect • LoD is a ``pseudo'' aspect because it cannot run in the current implementation of AspectJ, which doesn't allow declare warning to be defined on any pointcut with an if expression. UCI Feb 03
Join Point Form • The pointcuts ArgumentRule and AssociatedRule select the ``good'' join points. • ArgumentRuleselects those join points whose target is one of the arguments of the enclosing join point; UCI Feb 03
Join Point Form • AssociatedRule selects those join points whose target is in the set of locally returned ID's, and the ID's created in the siblings of the current node. UCI Feb 03
Map Dynamic Object Form (DOF) to LoD_JPF • We use LoD_JPF pointcut to check DOF: • Dynamic join point model is mapped to JPT. • Object is mapped to ID. • Method invocations are mapped to JPF join points. The enclosing join point is the parent in the control flow. UCI Feb 03
Map Lexical Class Form (LCF) to LoD_JPF • We use LoD_JPF to check LCF as follows. • Lexical join point model is mapped to JPT. Lexical join points are nodes in the abstract syntax tree • Class is mapped to ID. • Join points are signatures of call sites. The enclosing join point is the signature of the method in which the call site resides. To run the aspect, a suitable ordering has to be given to the elements of children: • all constructor calls, followed by local method calls, followed by the other join points. UCI Feb 03
AspectJ code • In AOSD 2003 paper with David Lorenz and Pengcheng Wu • DOF: AspectJ works well. Program uses most adaptive ingredients of AspectJ: *, cflow, this, target, etc. • LCF: AspectJ cannot do it. We sketch how to add statically executable advice to AspectJ. UCI Feb 03
package lawOfDemeter; public abstract class Any { public pointcut scope(): !within(lawOfDemeter..*) && !cflow(withincode(* lawOfDemeter..*(..))); public pointcut StaticInitialization(): scope() && staticinitialization(*); public pointcut MethodCallSite(): scope() && call(**(..)); public pointcut ConstructorCall(): scope() && call(*.new (..)); public pointcut MethodExecution(): scope() && execution(**(..)); public pointcut ConstructorExecution(): scope() && execution(*.new (..)); public pointcut Execution(): ConstructorExecution() || MethodExecution(); public pointcut MethodCall(Object thiz, Object target): MethodCallSite() && this(thiz) && target(target); UCI Feb 03
Class Any continued public pointcut SelfCall(Object thiz, Object target): MethodCall(thiz, target) && if(thiz == target); public pointcut StaticCall(): scope() && call(static * *(..)); public pointcut Set(Object value): scope() && set(* *.*) && args(value); public pointcut Initialization(): scope() && initialization(*.new(..)); } UCI Feb 03
package lawOfDemeter.objectform; import java.util.*; abstract class ObjectSupplier { protected boolean containsValue(Object supplier){ return targets.containsValue(supplier); } protected void add(Object key,Object value){ targets.put(key,value); } protected void addValue(Object supplier) { add(supplier,supplier); } protected void addAll(Object[] suppliers) { for(int i=0; i< suppliers.length; i++) addValue(suppliers[i]); } private IdentityHashMap targets = new IdentityHashMap(); } UCI Feb 03
package lawOfDemeter.objectform; public aspect Pertarget extends ObjectSupplier pertarget(Any.Initialization()) { before(Object value): Any.Set(value) { add(fieldIdentity(thisJoinPointStaticPart), value); } public boolean contains(Object target) { return super.containsValue(target) || Percflow.aspectOf().containsValue(target); } private String fieldIdentity(JoinPoint.StaticPart sp) { … } private static HashMap fieldNames = new HashMap(); } UCI Feb 03
package lawOfDemeter.objectform; aspect Check { private pointcut IgnoreCalls(): call(* java..*.*(..)); private pointcut IgnoreTargets(): get(static * java..*.*); after() returning(Object o):IgnoreTargets() { ignoredTargets.put(o,o); } after(Object thiz,Object target): Any.MethodCall(thiz, target) && !IgnoreCalls() { if (!ignoredTargets.containsKey(target) && !Pertarget.aspectOf(thiz).contains(target)) System.out.println( " !! LoD Object Violation !! " + thisJoinPointStaticPart/*[*/ + at(thisJoinPointStaticPart)/*]*/); } private IdentityHashMap ignoredTargets = new IdentityHashMap();} UCI Feb 03
package lawOfDemeter.objectform; aspect Percflow extends ObjectSupplier percflow(Any.Execution() || Any.Initialization()){ before(): Any.Execution() { addValue(thisJoinPoint.getThis()); addAll(thisJoinPoint.getArgs()); } after() returning (Object result): Any.SelfCall(Object,Object) || Any.StaticCall() || Any.ConstructorCall() { addValue(result); } } UCI Feb 03
Conclusions • Aspects and adaptiveness must work closely together to achieve best results. Crosscutting is closely linked to adaptiveness. • AspectJ and DemeterJ have been very well integrated (DAJ on Source Forge). • AP is a specialization of AOP and AOP is a specialization of AP. It goes both ways. • AspectJ is a really useful language but we are a little concerned about how difficult it was to debug the Law of Demeter checkers. UCI Feb 03
A O S D 2003 Boston, MA UCI Feb 03
A O S D 2003 Boston, MA UCI Feb 03
City = <routes> List(BusRoute) <flights> List(Flight). BusRoute = <cities> List(City). Flight = <cities> List(City). City routes BusRoute cities City (routes BusRoute cities City) { City -> BusRoute bypassing City BusRoute -> City bypassing City } source: City target: City UCI Feb 03