Integrating Demeter into AspectJ using Aspect

Download Report

Transcript Integrating Demeter into AspectJ using Aspect

Integrating Demeter into AspectJ
using Aspect-Oriented
Programming
Paul Freeman
COM3362 Final Homework
Review
Problem Posed
PARTS 1 & 2:
1. Produce the class graph cg from a Java program.
2. Read in a set of declared traversal strategies from an Aspect file
(Traversals.java):
declare traversal t1( ) : "from Basket to *";
3. Produce a traversal graph from each traversal strategy.
4. Using the interface of the AP Library available in DJ, generate an Aspect
that contains the traversal code for each traversal graph
(TraversalsImplementation.java).
4. Generate an Aspect containing test code that will test your traversal code
(TraversalsTest.java).
Problem Posed
PART 3:
Add a visitor declaration language to the traversal language:
declare visitors : Visitor1Interface;
declare traversal t1(Visitor1Interface) : "from Basket to *";
Defining the visitor methods in an interface (including edge and around
methods):
interface Visitor1Interface {
void before(A a);
void after(B host);
void after(C host);
void after_e(A host, B dest);
void around(C host, Subtraversal st);
void start();
void finish();
}
Problem Posed
PART 3 (cont.):
AspectJ should be used as follows:
ajc *.java
java Main > traversals.java ...
ajc *.java
java Main ...
// first compilation
// first run (stopped prematurely)
// second compilation
// second run
where:
first compilation:
- weaves the aspects that capture information about the user’s program into the
user’s program itself.
first run (of the user’s program is stopped prematurely):
- capture the classgraph, traversal graphs, and visitor interfaces
- produce the files TraversalsImplementation.java, TraversalsTest.java
second compilation:
- recompile the user’s program, weaving in the “first run” generated Traversal
aspects
second run:
- the actual run of the user’s program with the incorporated traversal code
Common Solutions
Capture of Strategies, Traversal Graphs, and Elements:
Methods used:
1. ClassGraph captured around a call to main(String[ ] args)
2. Strategies captured at parse of traversal file and stored in an intermediate data
structure
3. Each Strategy was used to create a TraversalGraph
2. nodeSets removed from the TG using the AP Library
3. the outgoingEdgeSets were removed from each node
4. Each outgoingEdgeSet was examined for the various edge types:
- construction edge
- inheritance edge
- alternation edge
5. the Visitor interfaces are examined for the methods declared.
Common Solutions
Code Generation:
Methods used:
1. The structures used to hold the various elements were then traversed to produce
the traversal code.
2. Test code was generated based on the Traversal Graphs constructed and the
names of the traversals read from the traversal declaration file.
What was learned
Integration of Demeter into AspectJ:
Production of the traversal code itself was done in a common fashion, but
methods used to capture and execute visitor advice varied.
Integration is possible but non-trivial.
In particular, implementation of the visitor methods, ‘around(Host, Subtraversal)’
and ‘around_e(Source, Destination, Subtraversal)’ are difficult to implement.
This is due to the fact that the user writes the body of the advice declared in the
visitor interface. And that there is possibility that a call of Subtraversal.apply() is
made, but it is not required. If apply() is not called from within the visitor’s
around advice, the traversal should not continue. However if apply is called, the
traversal should continue down the traversal path chosen, i.e.
apply(“edge_label”) or apply() could be called, OR no apply could be called at all.
(example on next slide)
What was learned
Integration of Demeter into AspectJ (example of major problem):
interface Visitor1{
around(Basket b, Subtraversal st);
}
class MyVisitor implements Visitor1{
around(Basket b, Subtraversal st){
if( path.equalsIgnoreCase(“All”) ){ st.apply(); }
else if( path.equalsIgnoreCase(“Fruit”) ){ st.apply(“f”); }
else if( path.equalsIgnoreCase(“Pencil”) ){ st.apply(“p”); }
else{ /* do nothing */ }
}
}
Summary of Solutions
Execution of Visitor advice:
Two different camps:
Execution of visitor advice based on join points within the traversal.
Insertion of visitor advice method calls into the traversal code at the
appropriate locations.
Summary of Solutions
Execution of visitor advice based on join points within the traversal
aspect TraversalsImplementation {
void Basket.t2(Visitor2 vt2) {
if (f != null) t2_f(vt2);
}
void Basket.t2_f(Visitor2 vt2) {f.t2(vt2);}
void Fruit.t2(Visitor2 vt2) {
if (w != null) t2_w(vt2);
}
void Fruit.t2_w(Visitor2 vt2) {w.t2(vt2);}
...
}
:
Summary of Solutions
Execution of visitor advice based on join points within the traversal (cont.):
Class MyVisitor implements Visitor2{
public void start( ){ System.out.println(“Visitor2: public void start( )”);
public void before(Basket basket0){
System.out.println("Visitor2: public void before(Basket basket0)");
}
}
aspect TraversalsTest {
pointcut visiting_Basket_t2(Basket _basket, Visitor2 myV_visitor2 ) : call(void t2(Visitor2) )
&& target(_basket) && args(myV_visitor2);
before (Basket _basket, Visitor2 myV_visitor2) :
visiting_Basket_t2(_basket, myV_visitor2) {
myV_visitor2.start();
myV_visitor2.before(_basket);
}
}
Summary of Solutions
Insertion of visitor advice method calls into the traversal code:
aspect TraversalsImplementation {
void Basket.t3(Visitor1 v1){
v1.start();
v1.before(this);
if(f != null) t3_f(v1);
v1.finish();
}
void Basket.t3_f(Visitor1 v1){
f.t3(v1);
}
...
}
Summary of Solutions
Insertion of visitor advice method calls into the traversal code:
class MyVisitor implements Visitor1{
public void before(Basket host){
System.out.println(“Visitor1: public void before(Basket host)”);
}
…
}
Summary of Solutions
Insertion of visitor advice method calls into the traversal code (around()’s):
aspect TraversalsImplementation {
void Basket.t3(Visitor1 v1){ v1.start(); v1.around(this, new Subtraversal());
v1.finish(); }
void Basket.t3_f(Visitor1 v1){f.t3(v1); }
void Basket.subtraversal(Visitor1 v1){ if(f != null) t3_f(v1); }
void Basket.subtraversal_f(Visitor1 v1){ if(f != null) t3_f(v1); }
pointcut Basket_apply(Basket host, Visitor1 v1): call(void Subtraversal.apply(Object))
&& this(v1) && args(host);
void around(Basket host, Visitor1 v1): Basket_apply(host, v1) { host.subtraversal(v1);
}
pointcut Basket_applyOnEdge(Basket host, Visitor1 v1, String edge):
call(void Subtraversal.apply(Object, String)) && this(v1) && args(host, edge);
void around(Basket host, Visitor1 v1, String edge): Basket_applyOnEdge(host, v1,
edge) {
if(edge.equals("f")){ host.subtraversal_f(v1); }
}
...
}
Summary of Solutions
Insertion of visitor advice method calls into the traversal code (around()’s):
class MyVisitor implements Visitor1{
public void around(Basket host, Subtraversal st){
st.apply(host);
}
…
}
Suggestions for future exercises:
Next Step:
Implementation of around methods that return values other than void.
Implementation of a functional visitor.
Implementation of multiple visitor traversals where the visitors can
communicate.