-------------------------------------------------------------------------- Advanced Software Development Fall 2003 CSG 260 --------------------------------------------------------------------------- Assignment 2 Due date: Oct. 2, 2003 -------------------------------------------------------------------------- This assignment is stored in file $ASD/hw/2 in file assign.txt -------------------------------------------------------------------------- I will grade your homeworks myself because the class is small. Please use the subject header: CSG 260 HW X so that I can easily filter your homework solutions. I prefer hard copy submission so that I don't have to print your solutions. Doug Orleans (dougo) is the key developer for DemeterJ and he also developed a good part of DJ. He maintains all Demeter software with Pengcheng Wu and Therapon Skotiniotis. You may turn in your hw for full credit up to two working days late. This means, if it is due on Thursday, you can turn it in the following Monday. If it is due on day x, it means 4.30 pm on that day. For late homework we will deduct 20% per day late, unless you present a very good reason to the teaching assistant. Please note that homework submission, besides hardcopy, is also electronic submission to csg260-grader. This will allow the teaching assistant to run your programs. Please send one zip files that includes the source code (no *.class files). In your subject line please start with: CSG 260 HW XY YOUR_FIRST_NAME In ADDITION, please turn in your answers in hardcopy at one of the following places: (1) Bring it to the class room and hand it to me. (2) In 161 Cullinane Hall: Put it into the teaching assistant's mailbox. (3) In 161 Cullinane Hall: Put it into my mailbox. (4) If all those possibilities don't work for you, slide it under my office door. ========= We reuse the abbreviations such as $ASD, $DJ already introduced in hw 1. ========= THEMES: Visitor Pattern, Automated Traversals using Strategies, Adaptive Programming in Java with DJ, Simulating an Automated Traversal Manually. READING: Read chapters 5, 6 of the AP book. Read Java book as necessary to understand enough of the Java programs which you need to modify in this homework. This homework is a 100% Java homework plus AspectJ. No Demeter syntax, except for the Demeter graphs (traversal strategies, class graphs, traversal graphs), is required. But a good understanding of DJ and AspectJ is necessary. Browse $DJ. Read about related tools which promote a traversal/visitor style to programming at: http://www.ccs.neu.edu/home/lieber/suntest.html A quote from the above URL: ==================== Visitor Support JJTree provides some basic support for the visitor design pattern. If the VISITOR option is set to true JJTree will insert an jjtAccept() method into all of the node classes it generates, and also generate a visitor interface that can be implemented and passed to the nodes to accept. ==================== The following two questions are designed so that you can find the unknowns without using the computer. You should find the unknowns without using the computer and at the end you may use the computer to check your answers. But remember that you get most of the educational value by studying the program and finding the unknowns manually. In the exams there will also be questions of this style. Question 1: -------------------------------------------------------------- Consider the following Java program and its output. The program solves the ITINERARY problem described in section 4.5 in the AP book at http://www.ccs.neu.edu/research/demeter/biblio/dem-book.html (see Gnomon Copy package). Some simplifications have been made: A Trip-object has only three parts, a Location-object has only one part, a list is implemented as a vector. Find the UNKNOWNs below. // Location.java class Location { String name; Location(String n){ name = n ;} } // Main.java import edu.neu.ccs.demeter.dj.*; import java.UNKNOWN1.*; import edu.neu.ccs.demeter.*; class Main { public Main() { super(); } static public void main(String args[]) throws Exception { // Build Trip-object Vector v1 = new Vector(); Location l1 = new Location("UNKNOWN2"); v1.UNKNOWN3(l1); Location l2 = new Location("UNKNOWN4"); v1.UNKNOWN5(l2); Location l3 = new Location("UNKNOWN6"); v1.UNKNOWN7(l3); Location l4 = new Location("UNKNOWN8"); v1.UNKNOWN9(l4); Trip a = new Trip(UNKNOWN10,UNKNOWN11,UNKNOWN12); System.out.println("DJ start "); UNKNOWN13 cg = Main.UNKNOWN14(); System.out.println(); UNKNOWN15 allLocations = new UNKNOWN16( UNKNOWN17 ,cg); System.out.println("---- TG begin "); System.out.println(allLocations); System.out.println("---- TG done "); System.out.println(); System.out.println("UNKNOWN18"); a.UNKNOWN19(UNKNOWN20); System.out.println(" DONE"); } public static ClassGraph buildClassGraph() { ClassGraph cg=new ClassGraph(true,false); // true: include all fields // false: do NOT include all non-void no-argument methods System.out.println("The DJ version is: " + cg.getVersion()); System.out.println("The class graph is" + "============================="); System.out.println(cg); System.out.println("end class graph " + "============================="); return cg; } } // Trip.java import java.UNKNOWN21.*; import edu.neu.ccs.demeter.dj.*; class Trip { Trip(Vector it, int d, int a) { itinerary = it; departure = d; arrival = a; } Vector itinerary; int arrival; int departure; void printItinerary(UNKNOWN22 allLocations) { allLocations.traverse(this, new UNKNOWN23() { void before (UNKNOWN24 host) {System.out.println("departure " + host.departure);} void before (UNKNOWN25 host) { System.out.println(host.name);} void after (UNKNOWN26 host) {System.out.println("arrival " + host.arrival);} }); } } // The output of the above program follows: DJ start The DJ version is: DJ version 0.8.4 The class graph is============================= Location = java.lang.UNKNOWN27 extends java.lang.Object. java.lang.String = extends java.lang.Object implements java.io.Serializable, java.lang.Comparable. java.lang.Object : java.lang.String | Location | Main | Trip | edu.neu.ccs.demeter.dj.Visitor | java.util.AbstractCollection common . java.io.Serializable : java.lang.String | java.util.Vector common . java.lang.Comparable : java.lang.String common . Main = extends java.lang.Object. Trip$1 = Trip extends edu.neu.ccs.demeter.dj.Visitor. Trip = java.util.UNKNOWN28 UNKNOWN30 int extends java.lang.Object. edu.neu.ccs.demeter.dj.Visitor : Trip$1 common extends java.lang.Object. java.util.Vector = extends java.util.AbstractList implements java.util.List, java.lang.Cloneable, java.io.Serializable. java.util.AbstractList : java.util.Vector common extends java.util.AbstractCollection implements java.util.List. java.util.AbstractCollection : java.util.AbstractList common extends java.lang.Object implements java.util.Collection. java.util.Collection : java.util.AbstractCollection | java.util.List common java.lang.Object. java.util.List : java.util.AbstractList | java.util.Vector common extends java.util.Collection. java.lang.Cloneable : java.util.Vector common . int = . edu.neu.ccs.demeter.dj.Collection = java.lang.Object. end class graph ============================= ---- TG begin Copy 0: Nodes: UNKNOWN31 java.lang.Object java.util.Vector java.util.AbstractList java.util.AbstractCollection java.util.Collection java.io.Serializable Location edu.neu.ccs.demeter.dj.Visitor Trip$1 java.util.List java.lang.Cloneable Edges: -> UNKNOWN32,itinerary,java.util.UNKNOWN33 :> java.util.Vector,java.util.AbstractList :> java.util.AbstractList,java.util.AbstractCollection :> java.util.AbstractCollection,java.util.Collection -> java.util.Collection,elements,java.lang.Object => java.lang.Object,UNKNOWN34 => java.lang.Object,Trip => java.lang.Object,edu.neu.ccs.demeter.dj.Visitor => edu.neu.ccs.demeter.dj.Visitor,Trip$1 -> Trip$1,this$0,Trip => java.lang.Object,java.util.AbstractCollection => java.util.AbstractCollection,java.util.AbstractList => java.util.AbstractList,java.util.Vector :> java.util.Vector,java.util.List :> java.util.List,java.util.Collection :> java.util.AbstractList,java.util.List Edges to other copies: ---- TG done UNKNOWN35 departure 9 Zurich Chur St. Moritz Pontresina arrival 17 UNKNOWN36 ================ Question 2 ------------------------------------------------------------------ Consider the following Java program that gathers information from A-objects. The output from the program is attached. PART 1: -------------------------------------------------------- Your task is to rewrite the following part of Main.java: String whereToGo = "from A to F"; TraversalGraph tg = new TraversalGraph(whereToGo ,cg); List result1 = a.gather(tg); without using DJ classes by writing methods that satisfy the Law of Demeter and that return the same List result1. Your methods will be spread over several classes. Run your program to make sure it returns a list of the correct length. Turn in your modified Java files. PART 2: -------------------------------------------------------- Find the UNKNOWNs below. For some unknowns there is a choice. Choose the simplest answer. Turn in your answers in the UNKNOWN list at the end. import edu.neu.ccs.demeter.dj.*; import java.UNKNOWN1.*; class A { A(B b, C c) { this.b = b; this.c = c; } B b; C c; List gather(TraversalGraph what){ List result = what.gather(this); System.out.println("Traversal Graph "); System.out.println(what); return result; } } class B { B(D d) { this.d = d; } D d; } class C {} class D { D(E ei, X xi){ e = ei; x = xi;} E e; X x; } class E { E(UNKNOWN2 fi){ f = fi;} UNKNOWN3 f; } class F { F(int ii){ i = ii;} int i; } import edu.neu.ccs.demeter.dj.*; import java.UNKNOWN4.*; class Main { public static void main(String[] args) { ClassGraph cg = new ClassGraph(true,false); // constructed by reflection System.out.println("Class graph"); System.out.println(cg); System.out.println("End of Class graph"); A a = new A ( new B( new UNKNOWN5( new E( new F(7) ), new UNKNOWN6( new F(9)) ) ), new C()); Strategy sg = new Strategy("from A through X to F"); TraversalGraph tg1 = new TraversalGraph(sg, cg); tg1.traverse(a, new UNKNOWN7()); String whereToGo = "UNKNOWN8"; TraversalGraph tg = new TraversalGraph(whereToGo ,cg); System.out.println(whereToGo); List result1 = a.gather(tg); System.out.println("List size = " + result1.size()); whereToGo = "UNKNOWN36 "; tg = new TraversalGraph(whereToGo ,cg); System.out.println(whereToGo); result1 = a.gather(tg); System.out.println("List size = " + result1.size()); whereToGo = "{A -> X X ->F}"; // same as whereToGo = "from A through X to F" except // that X is also a target; // The following strategy correctly specifies source and target // whereToGo = "{source:A -> X X ->target:F}"; tg = new TraversalGraph(whereToGo ,cg); System.out.println(whereToGo); result1 = a.gather(tg); System.out.println("List size = " + result1.size()); whereToGo = "{A ->F bypassing {X}}"; tg = new TraversalGraph(whereToGo ,cg); System.out.println(whereToGo); result1 = a.gather(tg); System.out.println("List size = " + result1.size()); } } import edu.neu.ccs.demeter.dj.Visitor; class MyVisitor extends Visitor { public void start() { System.out.println("begin"); } public void finish() { System.out.println("end"); } public void before(A o) { System.out.println("before A"); } public void after(A o) { System.out.println("after A"); } public void before(B o) { System.out.println("before B"); } public void after(B o) { System.out.println("after B"); } public void before(C o) { System.out.println("before C"); } public void after(C o) { System.out.println("after C"); } public void before(D o) { System.out.println("before D"); } public void after(D o) { System.out.println("after D"); } public void before(E o) { System.out.println("before E"); } public void after(E o) { System.out.println("after E"); } public void before(F o) { System.out.println("before F"); } public void after(F o) { System.out.println("after F"); } public void before(X o) { System.out.println("before X"); } public void after(X o) { System.out.println("after X"); } } class X { X(F fi){ f = fi;} F f; } The output: Class graph A = B C extends java.lang.Object. B = D extends java.lang.Object. java.lang.Object : B | C | A | D | E | X | java.util.AbstractCollection | GatherVisitor | F | Main | edu.neu.ccs.demeter.dj.Visitor common . C = extends java.lang.Object. D = E X extends java.lang.Object. E = F extends java.lang.Object. X = F extends java.lang.Object. GatherVisitor = java.util.Vector extends java.lang.Object. java.util.Vector = extends java.util.AbstractList implements java.util.List, java.lang.Cloneable, java.io.Serializable. java.util.AbstractList : java.util.Vector common extends java.util.AbstractCollection implements java.util.List. java.util.AbstractCollection : java.util.AbstractList common extends java.lang.Object implements java.util.Collection. java.util.Collection : java.util.AbstractCollection | java.util.List common java.lang.Object. java.util.List : java.util.AbstractList | java.util.Vector common extends java.util.Collection. java.lang.Cloneable : java.util.Vector common . java.io.Serializable : java.util.Vector common . F = int extends java.lang.Object. int = . Main = extends java.lang.Object. edu.neu.ccs.demeter.dj.Visitor : MyVisitor common extends java.lang.Object. MyVisitor = extends edu.neu.ccs.demeter.dj.Visitor. edu.neu.ccs.demeter.dj.Collection = java.lang.Object. End of Class graph begin before UNKNOWN9 before UNKNOWN10 before UNKNOWN11 before UNKNOWN12 before UNKNOWN13 after UNKNOWN14 after UNKNOWN15 after UNKNOWN16 after UNKNOWN17 after UNKNOWN18 end from A to F Traversal Graph Copy 0: Nodes: A B java.lang.Object D E F X Edges: -> A,b,B -> B,d,D -> D,e,E -> E,f,F -> D,x,X -> X,f,F Edges to other copies: List size = 2 UNKNOWN35 from A through X to F Traversal Graph Copy 0: Nodes: A B java.lang.Object D Edges: -> A,b,B -> B,d,D Edges to other copies: 1: -> D,x,X Copy 1: Nodes: java.lang.Object F X Edges: -> X,f,F Edges to other copies: List size = 1 {A -> X X ->F} Traversal Graph Copy 0: Nodes: A B java.lang.Object D X Edges: -> A,b,B -> B,d,D -> UNKNOWN19,UNKNOWN20,UNKNOWN21 Edges to other copies: 1: -> D,x,X Copy 1: Nodes: java.lang.Object F X Edges: -> X,f,F Edges to other copies: List size = 2 {A ->F bypassing {X}} Traversal Graph Copy 0: Nodes: A B java.lang.Object D E F Edges: -> UNKNOWN22,UNKNOWN23,UNKNOWN24 -> UNKNOWN25,UNKNOWN26,UNKNOWN27 -> UNKNOWN28,UNKNOWN29,UNKNOWN30 -> UNKNOWN31,UNKNOWN32,UNKNOWN33 Edges to other copies: List size = UNKNOWN34 ========== The DJ documentation is at: http://www.ccs.neu.edu/research/demeter/software/docs/api/ ====================== Cut here and turn in the following for both questions. Question ?: ================================================== UNKNOWN1 = UNKNOWN2 = UNKNOWN3 = UNKNOWN4 = UNKNOWN5 = UNKNOWN6 = UNKNOWN7 = UNKNOWN8 = UNKNOWN9 = UNKNOWN10 = UNKNOWN11 = UNKNOWN12 = UNKNOWN13 = UNKNOWN14 = UNKNOWN15 = UNKNOWN16 = UNKNOWN17 = UNKNOWN18 = UNKNOWN19 = UNKNOWN20 = UNKNOWN21 = UNKNOWN22 = UNKNOWN23 = UNKNOWN24 = UNKNOWN25 = UNKNOWN26 = UNKNOWN27 = UNKNOWN28 = UNKNOWN29 = UNKNOWN30 = UNKNOWN31 = UNKNOWN32 = UNKNOWN33 = UNKNOWN34 = UNKNOWN35 = UNKNOWN36 = Question 3: =========== Write an AspectJ program that prints a message to the output file whenever a method of some class C calls a method of class C. In other words, detect all local calls that happen during a particular execution. Print the join point object for each such call on a separate line. This is part of a Law of Demeter Checker written in AspectJ. Reuse the following utility class. // author: Pengcheng Wu import org.aspectj.lang.reflect.*; import org.aspectj.lang.*; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.SourceLocation; import java.util.*; class JPUtil { static String toString(JoinPoint jp) { SourceLocation sl = jp.getSourceLocation(); String fname = sl.getFileName(); int line = sl.getLine(); int col = sl.getColumn(); Object [] argsArray = jp.getArgs(); System.out.println("arguments"); for(int i=0; i>> " + jp.getSignature().toString() + " in " + fname + " line " + line + "(" + col + ") "; // + " args " + argsArray; // + " toLongString " + jp.toLongString(); } } Use a pointcut like: call(* *(..)) && ... and advice statements like: Object thisObject = thisJoinPoint.getThis(); Object targetObject = thisJoinPoint.getTarget(); Turn in your AspectJ program. Question 4: =========== Write an AspectJ program that prints the join point tree of execution and call join points. For each call and execution join point jp print: JPUtil.toString(jp); thisJoinPoint.getThis();thisJoinPoint.getTarget(); Indent before each call and execution and unindent after each call and execution. Turn in your AspectJ program. Note the alternating structure of the call and execution join points. A call join point contains an immediate execution join point. An execution join point contains several immediate call join points. Note also how the information at call join points differs from the information at execution join points. Question 5: =========== Do part B of hw 1 of the undergraduate class: http://www.ccs.neu.edu/home/lieber/courses/csu670/f03/hw/1/assign.html#PARTB This will show how DAJ works: http://daj.sourceforge.net/