Adaptive Aspect-Oriented Programming in AspectJ Karl J. Lieberherr Northeastern University Joint work of Demeter Research Group UCI Feb 03
Download
Report
Transcript Adaptive Aspect-Oriented Programming in AspectJ Karl J. Lieberherr Northeastern University Joint work of Demeter Research Group UCI Feb 03
Adaptive Aspect-Oriented
Programming in AspectJ
Karl J. Lieberherr
Northeastern University
Joint work of Demeter Research Group
UCI Feb 03
1
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
2
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
3
Adaptive Aspects
abstract public aspect RemoteExceptionLogging {
abstract pointcut logPoint();
abstract
after() throwing (RemoteException e): logPoint() {
log.println(“Remote call failed in: ” +
thisJoinPoint.toString() +
“(” + e + “).”);
}
}
public aspect MyRMILogging extends RemoteExceptionLogging {
pointcut logPoint():
call(* RegistryServer.*.*(..)) ||
call(private * RMIMessageBrokerImpl.*.*(..));
}
UCI Feb 03
4
A Different Kind of Adaptive
Aspect
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
5
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
6
Observation 1
• Many AspectJ programs are adaptive (designed for a
family of Java programs)
– Context: Java program or its execution tree
• 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
7
Observation 2
• Want to improve the adaptive capabilities of
AspectJ: AspectJ still leads to tangling and
duplication.
UCI Feb 03
8
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
9
Example of an Adaptive Method
in AspectJ (DAJ)
aspect FileSystemTraversals {
declare traversal:
void listAll():
"from CompoundFile to File"
(FileLister);
}
UCI Feb 03
10
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
11
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
12
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
13
Domain-specific aspect
languages
• What is a good infrastructure for this?
• Goes back to the old theme of Crista:
domain-specific aspect languages.
UCI Feb 03
14
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 metainformation 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
UCI Feb 03
15
the edges.
Top graph: subgraph of transitive closure of middle layer
A
B
C
Middle graph: Abstraction barrier
A
B
C
Bottom tree: select subtrees
B
A
UCI Feb 03
c1:C
c2:C
c3:C
16
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
17
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
18
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
19
Law of Demeter
(Join Point Form)
JPT(ID) =
[<target> ID]
<args> List(ID)
<children> List(JPT)
[<ret> ID].
List(S) ~ {S}.
UCI Feb 03
20
JPT(ID) =
[<target> ID]
<args> List(ID)
<children> List(JPT)
[<ret> ID].
target t2
ret r1
List(S) ~ {S}.
UCI Feb 03
E
target t2
args {a1,a2}
J
r1.foo1()
target null
a1.bar()
ret r3
t2.foo2()
r3.foo2()
21
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
22
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
23
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
24
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
25
Join Point Form
• The pointcuts ArgumentRule and
AssociatedRule select the ``good'' join
points.
• ArgumentRule selects those join points
whose target is one of the arguments of the
enclosing join point;
UCI Feb 03
26
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
27
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
28
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
29
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
30
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
31
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
32
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
33
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
34
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
35
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
36
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
37
UCI Feb 03
38
A O S D
UCI Feb 03
39
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
40
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
41
Domain-specific aspect
languages
• What is a good infrastructure for this?
• Goes back to the old theme of Crista:
domain-specific aspect languages.
UCI Feb 03
42
Aspect-Oriented Programming
with Extensible Plugins
• How can we integrate numerous domain
specific aspect languages?
• Idea: Use AspectJ as basic aspect language
and translate domain specific aspect
languages to AspectJ.
• Case study: Redo DAJ in this style.
• [email protected]
UCI Feb 03
43
Interfaces of Aspects
• For functionality
– Expects
– Provides
• For join points
– Import
– Export
UCI Feb 03
44
Everything reduced to classes and AspectJ aspects
Kinds of Aspects
•
•
•
•
•
Class Dictionary Aspect
Traversal Aspect
Traversal Advice Aspect
AspectJ Aspect
Class
UCI Feb 03
45
Import and export
Join points
Dynamic/lexical
Provide and expect
Something executable
Kinds of Aspects
• Class Dictionary Aspect
–
–
–
–
Imports: nothing (is a sink)
Exports: class graph nodes and edges
Expects: nothing (is a sink)
Provides: parser, numerous traversal advice (print,
copy, display, check, equal)
• Traversal Aspect
–
–
–
–
Imports: class graph nodes and edges
Exports: dynamic join points during traversal
Expects: traversal advice
Provides: (adaptive) methods
UCI Feb 03
46
Import and export
Join points
Dynamic/lexical
Provide and expect
Something executable
Kinds of Aspects
• Traversal Advice Aspect
–
–
–
–
Imports: object graph slice nodes and edges
Exports: dynamic join points during visitor methods
Expects: methods
Provides: visitor methods (advice)
• AspectJ Aspect
–
–
–
–
Imports: class graph nodes, dynamic join points
Exports: dynamic join points during advice
Expects: abstract methods and pointcuts
Provides: advice, introductions
UCI Feb 03
47
Join point examples
ClassDictionary Aspect
aspect FileSys [ClassDictionary] {
FileSystem = <root> CompoundFile EOF.
File : SimpleFile | CompoundFile common
<name> Ident.
SimpleFile = "simple".
CompoundFile = "compound" <contents>
FileList [<parent> CompoundFile].
FileList ~ "(" { File } ")".
EBNF
}
UCI Feb 03
48
Traversal Aspect
aspect FileSystemTraversals [Traversal] {
declare strategy: eachFile: "intersect(from
CompoundFile to File, down)";
declare traversal:
void listAll() : eachFile(FileLister);
declare strategy: down: "from * bypassing ->
*,parent,* to *";
declare strategy: up: "from * bypassing ->
*,contents,* to *";
Happens to be AspectJ code
}
UCI Feb 03
49
Need for Glue
• The class dictionary aspect and traversal
aspect. Use name mapping:
– CompoundFile, File, parent, content
• Need to check whether there is a path from
CompoundFile to File in the class graph
that is exported from the class dictionary
aspect.
UCI Feb 03
50
Glue Aspect
aspect FileSystemMethods [Cd_Traversal]
{
default name map;
// FileSys.CompoundFile =
// FileSystemTraversals.CompoundFile
// etc.
}
UCI Feb 03
51
AspectJ Aspect
aspect FileSystemMethods [AspectJ] {
File CompoundFile.getFile(Ident name) {
for (Iterator it =
contents.iterator(); it.hasNext();) {
File file = (File) it.next();
if (file.name.equals(name))
return file;
}
return null;
}
}
UCI Feb 03
52
Traversal Advice Aspect
aspect FileLister [TraversalAdvice] {
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();}
Happens to be a Java class
}
UCI Feb 03
53
Fred (AOSD 02): simplest AOP language: decision points, branches
LoD for Fred (D. Orleans)
• The set of potential preferred suppliers to a message-send
expression M in the body of a branch B is the union of
the objects in the following sets:
• the argument list A of the decision point E that caused
the invocation of B;
• the associated values of E, that is,
– the results of message-send expressions M' in the body of B
before M whose argument lists A' intersect with A;
– instances that were created in the control flow of the body of B
before M.
UCI Feb 03
54