Download presentation
Presentation is loading. Please wait.
Published byDale Lester Modified over 9 years ago
1
AOP and Aspect C++ presentation by Igor Kotenkov based on presentation by Andreas Gal, Daniel Lohmann and Olaf Spinczyk
2
Contents AOP with pure C++ AspectC++ AspectC++ Tool Support Summary
5
Templates Templates can be used to construct generic code. To actually use the code, it has to be instantiated. As preprocessor directives: –templates are evaluated at compile time –they do not cause any direct time overhead (if applied properly) Templates are typically used to implement generic abstract data types.
6
AOP with templates Templates allow us to encapsulate aspect code independently from the component code. Aspect code is “woven into” the component code by instantiating those templates. class Queue { … void enqueue(Item *item) { // adding item to the queue } Item *dequeue() { // remove item from the queue } }; temeplate Counting_Aspect : public Q { int counter; public: void enqueue(Item *item) { Q::enqueue(item); counter++; } Item *dequeue() { Item *res = Q::dequeue(item); if (counter > 0) counter--; return res; } // this method is added to the component code int count() const {return counter;} };
7
Weaving We can define a type alias (typedef) that combines both, component and aspect code: typedef Counting_Aspect CountingQueue; int main() { CountingQueue q; q.add(…); … }
8
Combining Aspects Weaving with multiple aspects: typedef Exception_Aspect > ExceptionsCountingQueue; or typedef Counting_Aspect > ExceptionsCountingQueue; for counting first and then – checking for exceptions. Implementation of the aspects should be independent of ordering, so it will be no problem with either ordering we will apply.
9
Limitations Joinpoint types –no distinction between function call and execution; –no advice for attribute access; –no advice for private member functions. Quantification –no flexible way to describe the target components; –applying the same aspect to classes with different interfaces is impossible or ends with excessive template metaprogramming. Scalability –the wrapper code can easily outweigh the aspect code; –explicitly defining the aspect order for every affected class; –makes code hard to understand and debug. “AOP with pure C++ is like OOP with pure C”
10
Conclusions C++ templates can be used for separation of concerns in C++ code without special tool support However, the lack of expressiveness and scalability restricts these techniques to projects with: –only small number of aspects; –few or no aspect interactions; –aspects with a non-generic nature; –component code that is “aspect-aware”.
11
Aspect C++ Basic features within Queue example –aspect, advice, execution, call –introduction –joinpoints, pointcut expressions Advanced concepts –the Joinpoint API –abstract aspects and aspect inheritance –aspects ordering –aspect instantiation Summary
12
ElementCounter aspect aspect ElementCounter { int counter; ElementCounter() { counter = 0; } advice execution(“% util::Queue::enqueue(…)”) : after() { ++counter; printf(“ Aspect ElementCounter: # of elements = %d\n”, counter); } advice execution(“% util::Queue::dequeue(…)”) : after() { if (counter > 0) --counter; printf(“ Aspect ElementCounter: # of elements = %d\n”, counter); } }; Introducing new aspect. An aspect starts with word aspect and is syntactically much like a class. Like a class, an aspect can define data members, constructors and so on.
13
ElementCounter aspect aspect ElementCounter { int counter; ElementCounter() { counter = 0; } advice execution(“% util::Queue::enqueue(…)”) : after() { ++counter; printf(“ Aspect ElementCounter: # of elements = %d\n”, counter); } advice execution(“% util::Queue::dequeue(…)”) : after() { if (counter > 0) --counter; printf(“ Aspect ElementCounter: # of elements = %d\n”, counter); } }; Giving after adviceThis pointcut expression denotes where the advice shoud be given.
14
Introduction The aspect is not the ideal place to store the counter, because it is shared between all Queue instances Ideally, counter becomes a member of Queue So, we will: –move the counter into Queue by introduction; –expose context about the aspect invocation to access the current new instance.
15
Introduction - continue aspect ElementCounter { private: advice “util::Queue” : int counter; public: advice “util::Queue” : int count {return counter;} const ElementCounter() { counter = 0; } advice execution(“% util::Queue::enqueue(…)”) && that(queue) : after(util::Queue& queue) { ++queue.counter; printf(“ Aspect ElementCounter: # of elements = %d\n”, queue.count()); } advice execution(“% util::Queue::dequeue(…)”) && that(queue) : after(util::Queue& queue) { if (queue.count() > 0) --queue.counter; printf(“ Aspect ElementCounter: # of elements = %d\n”, queue.count()); } advice execution(“% util::Queue::Queue(…)”) && that(queue) : before(util::Queue& queue) { queue.counter = 0; } }; Introducing a public method to read the counter Introduces a new data member counter into all classes denoted by pointcut “util::Queue” A context variable queue is bound to that. It has to be an util::Queue. It is used to access the current instance // within the constructor advice we ensure, that counter gets initialiazed
16
Joinpoints A joinpoint denotes a position to give advise: –Code joinpoint (control flow): execution of a function call to a function –Name joinpoints a named C++ program entity (identifier) class, function, method, type namespace Joinpoints are given by pointcut expressions –a pointcut expression describes a set of joinpoints
17
Pointcut Expressions Pointcut expressions are made from: –match expressions, e.g. “% util::Queue::enqueue(…)” are matched against C++ program entities (name joinpoints) support wildcards –pointcut functions, e.g. execution(…), call(…), that(…), within(…), cflow(…) execution: all points in the control flow, where a function is about to be executed (code joinpoints) call: all points in the control flow, where a function is about to be called (code joinpoints) Pointcut functions can be combined –using logical connectors: &&, ||, ! –example: call(“% util::Queue::enqueue(…)”) && within(“% main(…)”) !cflow(execution(“% util::~Queue()”))
18
Advice Advice to functions –before advice advice code is executed before the original code advice may read/modify parameter values –after advice advice code is executed after the original code advice may read/modify return value –around advice advice code is executed instead of the original code original code may be executed explicitly: tjp->proceed() Introductions –additional methods, data members, etc. are added to the class –can be used to extend the interface of a class or namespace
19
Error Handling We want to check the following constraints: –enqueue() is never called with a NULL item –dequeue() is never called on an empty queue In a case of an error an exception should be thrown To implement this the advice needs an access to –the parameter passed to enqueue() –the return value returned by dequeue()
20
ErrorException namespace util { class QueueInvalidItemError {}; class QueueEmptyError {}; } aspect ErrorException { advice execution(“% util::Queue::enqueue(…)”) && args(item) : before(util::Item* item) { if (item == NULL) throw util::QueueInvalidItemError(); } advice execution(“% util::Queue::dequeue(…)”) && result(item) : after(util::Item* item) { if (item == NULL) throw util::QueueEmptyError(); } };
21
Thread Safety Protect the queue by a mutex object To implement this, we need to –introduce a mutex variable into class Queue –lock it before execution of enqueue/dequeue –unlock it after execution of enqueue/dequeue The implementation should be exception safe –in the case of exception the “after” advice should called also –solution: around advice
22
LockingMutex aspect LockingMutex { advice “util::Queue” : os::Mutex lock; pointcut sync_methods() = “% util::Queue::%queue(…)”; advice execution(sync_methods()) && that(queue) : around(util::Queue& queue) { queue.lock.enter(); try { tjp->proceed(); } catch(…) { queue.lock.leave(); throw; } queue.lock.leave(); } };
23
Queue Example Summary The Queue example has presented the most important features of the AspectC++ language –aspect, advice, joinpoint, pointcuts, introduction, etc. Additionally, AspectC++ provides some more advanced concepts and features –to increase the expressive power of aspectual code –to write broadly reusable aspects –to deal with aspect interdependence and ordering
24
Advanced Concepts The Joinpoint API –provides a uniform interface to the aspect invocation context Abstract Aspects and Aspect Inheritance Aspects Ordering –allows to specify the invocation order of multiple aspects –Important in the case of inter-aspect dependencies Aspect Instantiation –allows to implement user-defined aspect instantiation models
25
The Joinpoint API Inside the advice body, the current joinpoint context is available via the implicitly passed tjp variable: advice … { struct JoinPoint { … } *tjp;// implicitly available in advice code You have already seen how to use tjp: tjp->proceed() to execute the original code in around advice The joinpoint API provides a rich interface –to expose context independently of the aspect target –this is especially useful in writing reusable aspect code
26
The Joinpoint API struct JoinPoint { // result type of a function typedef JP-specific Result; // object type (initiator) typedef JP-specific That; // object type (receiver) typedef JP-specific Target; // returns the encoded type of the joinpoint // (result conforms with C++ ABI V3 spec) static AC::Type type(); // the same for result static AC::Type resulttype(); // the same for an argument static AC::Type argtype(int n); // returns an unique id for this joinpoint static unsigned int id(); // returns joinpoint type of this joinpoint // (call, execution, …) static AC::JPType jptype(); }; // number of arguments of a function call static int args(); // textual representation of this joinpoint static const char* signature(); // returns a pointer to the n’th argument // value of a function call void* arg(int n); // returns a pointer to the result value of a // function call Result* result(); // returns a pointer to the object initiating a call That* that(); // returns a pointer to the object that is target of a call Target* target(); // executes the original code in an around advice void proceed(); // returns the runtime action object AC::Action& action();
27
Abstract Aspects and Inheritance Aspects can inherit from other aspects –reusing aspect definitions –overriding methods and pointcuts Pointcuts can be pure virtual –postponing the concrete definition to derived aspects –an aspect with a pure virtual pointcut is called abstract aspect Common usage: resusable aspect implementation –Abstract aspect defines advice code, but pure virtual pointcuts –Aspect code uses the joinpoint API to expose context –Concrete aspect inherits the advice code and overrides pointcuts
28
Abstract Aspects and Inheritance #include “mutex.h” aspect LockingA { pointcut virtual sync_classes() = 0; pointcut virtual sync_methods() = 0; advice sync_classes() : os::Mutex lock; advice execution(sync_methods()) : around() { tjp->that()->lock.enter(); try { tjp->proceed(); } catch(…) { tjp->that()->lock.leave(); throw; } tjp->that()->lock.leave(); } };
29
Abstract Aspects and Inheritance #include “mutex.h” aspect LockingA { pointcut virtual sync_classes() = 0; pointcut virtual sync_methods() = 0; advice sync_classes() : os::Mutex lock; advice execution(sync_methods()) : around() { tjp->that()->lock.enter(); try { tjp->proceed(); } catch(…) { tjp->that()->lock.leave(); throw; } tjp->that()->lock.leave(); } }; #include “LockingA.ah” aspect LockingQueue : public LockingA { pointcut sync_classes() = “util::Queue”; pointcut sync_methods() = “% util::Queue::%queue(…)”; };
30
Aspect Ordering Aspects should be independent of other aspects –however, sometimes inter-aspect dependencies are unavoidable –example: locking should be activated before any other aspect Order advice –the aspect order can be defined by order advice advice pointcut-expr : order(high, …, low) –different aspect orders can be defined for different pointcuts Example: advice “% util::Queue::%queue(…)” : order(“LockingQueue”, “%” && ! “LockingQueue”)
31
Aspect Instantiation Aspects are singeltons by default –aspectof() returns pointer to one-and-only aspect instance By overriding aspectof() this can be changed –e.g. one instance per client or one instance per thread aspect MyAspect { // … static MyAspect* aspectof() { static __declspec(thread) MyAspect* theAspect = NULL; if (theAspect == NULL) theAspect = new MyAspect(); return theAspect; } };
32
Summary AspectC++ facilitates AOP with C++ –AspectJ like syntax and semantics Full obliviousness and quantification –aspect code is given by advice –joinpoints are given declaratively by pointcuts –Implementation of crosscutting concerns is fully encapsulated in aspects Good support for reusable and generic aspect code –aspect inheritance and virtual pointcuts –joinpoint API
33
Tool Support ac++ compiler –open source and the base of other tools AspectC++ add-in for MS Visual Studio –commercial product AspectC++ plugin for Eclipse (ACDT) –open source
34
About ac++ www.aspect.org (Linux, Win32, Solaris, source, docs, etc.)www.aspect.org Transforms AspectC++ to C++ code –machine code is created by the back-end (cross-)compiler –supports g++ and Visual C++ specific language extentions Current version 0.9 (<1.0) –no optimizations for compilation speed –no weaving in templates –but already more than a proof of concept
35
Aspect Transformations Aspects are transformed to ordinary C++ classes One static aspect instance is created by default Advice becomes a member function “Generic advice” becomes a template member function A function call is replaced by a wrapper function A local class with the wrapper function invokes the advice code for the joinpoint The transformed code is built using C++ compiler
36
Pros and Cons AOP with pure C++ + no special tool required -requires in-depth understanding of C++ templates -the component code has to be aspect-aware -no pointcut concern, no match expressions AspectC++ + ac++ transforms AspectC++ into C++ + various joinpoint types + support for advanced AOP concerns: cflow, joinpoint API - longer compilation time
37
Roadmap Parser –full support of templates. Will accept g++ and VC++ STLs –better performance Advice for object access, for object instantiation Weaving in macro-generated code cflow with context variables Dependancy handling
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.