-------------------------------------------------------------------------- Software Engineering Fall 2002 COM 3205 --------------------------------------------------------------------------- Assignment 2 Due date: Oct. 10, 2002 -------------------------------------------------------------------------- This assignment is stored in file $SE/hw/2 in file hw2-SE.txt -------------------------------------------------------------------------- Topic: Implementing a Crosscutting Style Rule In hw 1 you wrote a requirement document for checking the Law of Demeter. In this hw we write a tool that approximates the Law of Demeter. The tool has the following requirement: Consider a Java program P while it is executing. For each method call which is a local method call, i.e., it is of the form this.foo(..), print the message: "local call". Implement your tool dynamically, using AspectJ. Hint: There are two basic ways you can write your program: Singleton Aspect Solution and Per-Object Aspect Solution. 1. [Singleton Aspect Solution] Write a singleton aspect that captures all method calls and checks whether the target object is the current object. // author: Pengcheng Wu import org.aspectj.lang.reflect.*; import org.aspectj.lang.*; aspect LoDPointCuts { pointcut Call(Object thisObject,Object targetObject): this(thisObject) && target(targetObject) && call(* *(..)) && !within(LoD..*); ... before(Object thisObject,Object targetObject): Call(thisObject,targetObject) { if (thisObject == targetObject) ... // print message: "local call" } } 2. [Per-Object Aspect Solution] Write an aspect that will be created for every object that is the executing object (i.e., "this") at any method call and check for the thisJoinPoint object whether the target object is the current object. In the AspectJ documentation we read: If an aspect A is defined perthis(Pointcut), then one object of type A is created for every object that is the executing object (i.e., "this") at any of the join points picked out by Pointcut. The advice defined in A may then run at any join point where the currently executing object has been associated with an instance of A. // author: David H. Lorenz import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.SourceLocation; class Any { pointcut scope(): !within(lawOfDemeter.*); // not in this package pointcut Call(): scope() && call(* *(..)); // any call }; public aspect LoD perthis (Any.Call()) { ... before(): Any.Call() { if (thisJoinPoint.getTarget() == thisJoinPoint.getThis()) { System.out.println(JPUtil.toString(thisJoinPoint)); System.out.println(" *** OK, local call"); return; } } } class JPUtil { static String toString(JoinPoint jp) { SourceLocation sl = jp.getSourceLocation(); String fname = sl.getFileName(); int line = sl.getLine(); int col = sl.getColumn(); return " >>> " + jp.getSignature().toString() + " in " + fname + " line " + line + "(" + col + ") "; } } Comparing the Singleton-Aspect-Solution with the Per-Object-Aspect-Solution: The Singleton-Aspect-Solution is simpler but makes it harder to talk about connections between join points. This is convenient for checking the full version of the Law of Demeter. The Per-Object-Aspect-Solution can be easily extended to keep track of the previous join point which is handy to check whether the target is an argument of the method, for example. Implement both the Singleton-Aspect-Solution and the Per-Object-Aspect-Solution and turn in both programs. Turn in your test program and the output produced by the two solutions. To install AspectJ in your environment, see: http://www.ccs.neu.edu/home/lieber/com3205/f02/CCS_AspectJ_Usage.html