Session 2: AspectJ

21
Session 2: AspectJ Mark Stobbe September 13, 2007 1

description

Session 2: AspectJ. Mark Stobbe September 13, 2007. Overview. Ingredients for Aspect Oriented Languages Join Point Model The Big Players Who beats who Language-specific Development-specific Loose ends. Ingredients. Join Point Model Join points Pointcuts Advice Composition Naming - PowerPoint PPT Presentation

Transcript of Session 2: AspectJ

Page 1: Session 2: AspectJ

Session 2: AspectJMark Stobbe

September 13, 2007

1

Page 2: Session 2: AspectJ

Overview

• Ingredients for Aspect Oriented Languages– Join Point Model

• The Big Players• Who beats who– Language-specific– Development-specific

• Loose ends

2

Page 3: Session 2: AspectJ

Ingredients• Join Point Model– Join points– Pointcuts– Advice

• Composition• Naming• Abstraction and concretization• Exposing state• Inter-type declarations• Weaver

3

Page 4: Session 2: AspectJ

Join points – up-close

4

public class Example{ int x; public static void main(String[] args) { Example ex = new Example(); ex.func(); }

public Example() { x = 10; }

public int func() { return x; }}

public class Example{ int x; public static void main(String[] args) { Example ex = new Example(); ex.func(); }

public Example() { x = 10; }

public int func() { return x; }}

3

6

78

910

4 5

1112

13

1. Before execution(void Example.main(String[])) 2. Before call(Example()) 3. Before execution(Example()) 4. Before set(int Example.x) 5. After set(int Example.x) 6. After execution(Example()) 7. After call(Example()) 8. Before call(int Example.func()) 9. Before execution(int Example.func())10. Before get(int Example.x)11. After get(int Example.x)12. After execution(int Example.func())13. After call(int Example.func())14. After execution(void Example.main(String[]))

within(Example)

withincode(int Example.func())

cflow(execution(Example.new()))

1-14

10-11

3-6

cflowbelow(execution(int Example.func()))10-11

12

14

Page 5: Session 2: AspectJ

Answering question

5

Answer1. Before2. Around3. After

QuestionAnother question that I have is about precedence. Imagine defining before, after and around advices for the same pointcut, I wonder what the execution order of the advices will be? Will the order be before, around and then after or the other way around? (Alesya)

Page 6: Session 2: AspectJ

Answering question

6

Answercflow is the collection of join points flowing from the argument pointcut. This means that cflow(P) && cflow(Q) is the intersection of the two collections, while cflow(P && Q) means that you first combine the pointcuts P and Q, and all the join points flowing from that are in this collection.

QuestionCan you please discuss the primitive pointcut cflow in detail? I am particularly interested in the semantics of the composition of those pointcuts: cflow(P) && cflow(Q) and cflow(P && Q). This is explained briefly in the Programming Guide, but I find it very difficult to understand. Perhaps you can give a clear, concrete example? (Martijn)

Page 7: Session 2: AspectJ

public aspect ExampleAspect { pointcut P(): execution(* Example.P(..)); pointcut Q(): execution(* Example.Q(..));

pointcut flowP(): cflow(P()) && within(Example); pointcut flowQ(): cflow(Q()) && within(Example); pointcut flowPAndflowQ(): cflow(P()) && cflow(Q()) && within(Example);}

public aspect ExampleAspect { pointcut P(): execution(* Example.P(..)); pointcut Q(): execution(* Example.Q(..));

pointcut flowP(): cflow(P()) && within(Example); pointcut flowQ(): cflow(Q()) && within(Example); pointcut flowPAndflowQ(): cflow(P()) && cflow(Q()) && within(Example);}

Giving example

7

public class Example { public void P() { Q(); } public void Q() { } public static void main(String[] args) { new Example().P(); }}

public class Example { public void P() { Q(); } public void Q() { } public static void main(String[] args) { new Example().P(); }}

Flow from P - execution(void Example.P())Flow from P - call(void Example.Q())Flow from P - execution(void Example.Q())Flow from Q - execution(void Example.Q())Flow from P && flow from Q - execution(void Example.Q())

Flow from P - execution(void Example.P())Flow from P - call(void Example.Q())Flow from P - execution(void Example.Q())Flow from Q - execution(void Example.Q())Flow from P && flow from Q - execution(void Example.Q())

Page 8: Session 2: AspectJ

Answering question

8

AnswerThe difference between cflow and cflowbelow is whether the argument pointcut should be taken included or excluded. The difference between within and cflow is that within works on a TypePattern, while cflow works on a Pointcut.

QuestionWhat is the difference between cflow and cflowbelow, and cflow and within? Is within just a more specific version of cflow? (Martijn)

Page 9: Session 2: AspectJ

public aspect ExampleB { pointcut P(): execution(* Example.P(..)); pointcut flowP(): cflow(P()) &&

within(Example);}

public aspect ExampleB { pointcut P(): execution(* Example.P(..)); pointcut flowP(): cflow(P()) &&

within(Example);}

Giving example

9

public class Example { public void P() { Q(); } public void Q() { } public static void main(String[] args) { new Example().P(); }}

public class Example { public void P() { Q(); } public void Q() { } public static void main(String[] args) { new Example().P(); }}

execution(void Example.P())call(void Example.Q())execution(void Example.Q())

execution(void Example.P())call(void Example.Q())execution(void Example.Q())

public aspect ExampleA { pointcut P(): execution(* Example.P(..)); pointcut flowP(): cflowbelow(P()) &&

within(Example);}

public aspect ExampleA { pointcut P(): execution(* Example.P(..)); pointcut flowP(): cflowbelow(P()) &&

within(Example);}

call(void Example.Q())execution(void Example.Q())call(void Example.Q())execution(void Example.Q())

Page 10: Session 2: AspectJ

Answering question

10

AnswerLine and Point are a subclass of FigureElement, this means the type matches and therefore you will indeed receive multiple matches for Line.incrXY and Point.incrXY. You can always specify precisely Line.incrXY(int,int) in your pointcut, if you only want that specific pointcut. Or you can use cflowbelow to retrieve only the first call to a FigureElement.incrXY call.

QuestionWhen you have something like:receptions(void FigureElement.incrXY(int, int)) and the example from Fig. 1 in the 2001-ecoop paper. If you call Line.incrXY(int,int) it will match, but what if that method forwards the call to Point.incrXY(int,int)? Will it match again? And if so, is there a way to prevent this bubbling up effect? Or don't you need this in practice anyway? But at the top of page 17 they seem to say that you can do that with cflow, but it's still a bit unclear. Is this indeed the way to do it? (Christiaan)

Page 11: Session 2: AspectJ

public aspect ExampleAspect { pointcut all(): execution(* FigElem.move(..)); pointcut first(): all() && !cflowbelow(all());}

public aspect ExampleAspect { pointcut all(): execution(* FigElem.move(..)); pointcut first(): all() && !cflowbelow(all());}

Giving example

11

public class Example { public static void main(String[] args) { new Line().move(); new Point().move(); }}

interface FigElem { public void move(); }

class Line implements FigElem { Point p; public void move() { p.move(); }}class Point implements FigElem { public void move() { }}

public class Example { public static void main(String[] args) { new Line().move(); new Point().move(); }}

interface FigElem { public void move(); }

class Line implements FigElem { Point p; public void move() { p.move(); }}class Point implements FigElem { public void move() { }}

First: execution(void Line.move()) execution(void Point.move())

First: execution(void Point.move())

First: execution(void Line.move()) execution(void Point.move())

First: execution(void Point.move())

Page 12: Session 2: AspectJ

Big Players

• For Java– AspectJ– AspectWerkz– JBoss AOP– Spring AOP

• For non-Java– AspectC++– Others, including comparison, can be found here:

http://janus.cs.utwente.nl:8000/twiki/bin/view/AOSDNET/CharacterizationOfExistingApproaches

@AspectJ

Spring 2.0 AOP includes AspectJ

12

Page 13: Session 2: AspectJ

Comparison - Syntax

Language-like vs. Annotations vs. XML• Concise and natural• Language support, own compiler• XML more familiar, easier to write tools• Fine-grained annotations

13Source: Mik Kersten – AOP Tools comparison

Page 14: Session 2: AspectJ

Answering question

14

AnswerIn AspectJ, no. There are a limited number of possible join points and since Java only allows for annotations outside methods, it is not possible. A workaround would be to extract the code into a method.

QuestionThe paper and tutorials on AspectJ say that the three types of advice that are available - before, after and around - allow applying advice to methods. But what if I want to insert a logging statement somewhere in the middle in the method code? Or when I do debugging and I want to see the intermediate results, I would have a log.debug statement inside a method. Is it possible to somehow accomplish that with AspectJ? I could think of writing a pointcut for every logging (debugging) statement that's in the middle of the method. But I was wondering if there is another way of doing this? (Alesya)

Page 15: Session 2: AspectJ

Comparison - Join points

Expressiveness vs. simplicity• Less join points, less to understand• Regular Expressions, strong but hard to read

Source: Mik Kersten – AOP Tools comparison15

Page 16: Session 2: AspectJ

Comparison - Weaver

Compile-Time vs. Run-Time• Some join points always require RT check, like: cflow and instanceof

• Static-checks makes easy programming• Fast compiling or fast running

16Source: Mik Kersten – AOP Tools comparison

Page 17: Session 2: AspectJ

Answering question

17

AnswerAspectJ tries solve most of these at compile-time. The overhead will then be a simple call to the advice body, which most of the time can be inlined by the virtual machine. Some pointcuts cannot be statically inferred, for example when using cflow or instanceof, these have an additional runtime check. In the paper they claim this overhead is relative small.

QuestionAt chapter 3.3 in the paper, they state that upon arrival at a join point, all advice in the system is examined to see whether any apply at the join point. It collects all advices and try to match those with the current evaluated method/function. Can this have some sort of influence on the system performance (especially on more advice given)? (Robin)

Page 18: Session 2: AspectJ

Answering question

18

AnswerBoth. The compiler is the static weaver, trying to weave all aspects at compile-time. The runtime library provides some extra classes, for example: JoinPoint. It is also used for runtime pointcuts like cflow and instanceof.

QuestionAt chapter 4 they say that the AspectJ language uses a compiler. At chapter 3.3 they talk about runtime (if I'm correct though). What's the implementation? Is it both a compiler and runtime library or just the compiler? (Robin)

Page 19: Session 2: AspectJ

Comparison - IDE

• Special AOP support• Normal debugging• No refactoring• No UML

19Source: Mik Kersten – AOP Tools comparison

Page 20: Session 2: AspectJ

Answering question

20

AnswerFor most editors there are tools written to support AspectJ or similar. These can again be used by developers to build their own tools on top. If you want to build support for your own IDE, AspectJ offers you the ADJE API.

QuestionAspectJ and IDE integration: are there tools that allow for easy integration, like some tool that tells given some pointcut where it will crosscut the program (/source code)? Or should every IDE extension implement this logic itself? (Peter)

Page 21: Session 2: AspectJ

Loose ends

21

AnswerIt is possible to create an abstract aspect, which can be implemented by another aspect. This aspect will then have to implement the abstract pointcuts defined in the abstract aspect. It is useful for creating general-purpose aspects.

QuestionIs it possible for an aspect to extend another aspect (maybe that would be another way of doing the MoveTracking and Mobile examples?). Or would that just come down to re-using the pointcuts? (Peter)