Download presentation
Presentation is loading. Please wait.
1
Mira Mezini Klaus Ostermann Aspect-Oriented Software Development, 2004
2
Outline Caesar 3. The Caesar Model -The observer pattern in Caesar. -Related work. 1. Requirements on Language Support 2. JPI: Joint Point Interception approach observer design pattern - The “observer design pattern”. - JPI deficiencies.
3
Relevant Concepts: “Tyranny of the dominant decomposition”. Cross-cutting models/concerns. Code scattering and tangling. JPI: the Joint-Point Interception approach.
4
The problem – an Example
9
Requirements on Language Support 1.Multi-Abstraction Aspect Modules 2.Aspect Composition 3.Reuse of Aspect Implementation and Bindings 4.Aspectual Polymorphism
10
Joint Point Interception JPI approach has disadvantages. JPIs are still the main primitives of AOP. Higher level constructs are to be added on top of JPIs and advices. observer pattern The problems with JPI are presented through the observer pattern in AspectJ.
11
A Graphics Software System Point … …… Shape Line Screen observer pattern The observer pattern 1 Observer Subject Abstract Observer Observer Subject Color Observer
12
observer pattern The observer pattern 2 public abstract aspect ObserverProtocol { protected interface Subject { } protected interface Observer { } private WeakHashMap perSubjectObservers; protected List getObservers(Subject s) { if (perSubjectObservers == null) perSubjectObservers = new WeakHashMap(); List observers = (List) perSubjectObservers.get(s); if ( observers == null ) { observers = new LinkedList(); perSubjectObservers.put(s, observers); } return observers; } … Declaring an abstract aspect public abstract aspect ObserverProtocol { protected interface Subject { } protected interface Observer { } private WeakHashMap perSubjectObservers; protected List getObservers(Subject s) { if (perSubjectObservers == null) perSubjectObservers = new WeakHashMap(); List observers = (List) perSubjectObservers.get(s); if ( observers == null ) { observers = new LinkedList(); perSubjectObservers.put(s, observers); } return observers; } … Marker Interfaces public abstract aspect ObserverProtocol { protected interface Subject { } protected interface Observer { } private WeakHashMap perSubjectObservers; protected List getObservers(Subject s) { if (perSubjectObservers == null) perSubjectObservers = new WeakHashMap(); List observers = (List) perSubjectObservers.get(s); if ( observers == null ) { observers = new LinkedList(); perSubjectObservers.put(s, observers); } return observers; } … Hash Field public abstract aspect ObserverProtocol { protected interface Subject { } protected interface Observer { } private WeakHashMap perSubjectObservers; protected List getObservers(Subject s) { if (perSubjectObservers == null) perSubjectObservers = new WeakHashMap(); List observers = (List) perSubjectObservers.get(s); if ( observers == null ) { observers = new LinkedList(); perSubjectObservers.put(s, observers); } return observers; } … Allocating a List of Observers for any Subject public abstract aspect ObserverProtocol { protected interface Subject { } protected interface Observer { } private WeakHashMap perSubjectObservers; protected List getObservers(Subject s) { if (perSubjectObservers == null) perSubjectObservers = new WeakHashMap(); List observers = (List) perSubjectObservers.get(s); if ( observers == null ) { observers = new LinkedList(); perSubjectObservers.put(s, observers); } return observers; } …
13
observer pattern The observer pattern 3 Adding and removing observers … public void addObserver(Subject s,Observer o){ getObservers(s).add(o); } public void removeObserver(Subject s,Observer o){ getObservers(s).remove(o); } abstract protected void updateObserver(Subject s, Observer o); abstract protected pointcut subjectChange(Subject s); after(Subject s) : subjectChange(s) { Iterator iter = getObservers(s).iterator(); while ( iter.hasNext() ) updateObserver(s, ((Observer)iter.next())); } Abstract members … public void addObserver(Subject s,Observer o){ getObservers(s).add(o); } public void removeObserver(Subject s,Observer o){ getObservers(s).remove(o); } abstract protected void updateObserver(Subject s, Observer o); abstract protected pointcut subjectChange(Subject s); after(Subject s) : subjectChange(s) { Iterator iter = getObservers(s).iterator(); while ( iter.hasNext() ) updateObserver(s, ((Observer)iter.next())); } … public void addObserver(Subject s,Observer o){ getObservers(s).add(o); } public void removeObserver(Subject s,Observer o){ getObservers(s).remove(o); } abstract protected void updateObserver(Subject s, Observer o); abstract protected pointcut subjectChange(Subject s); after(Subject s) : subjectChange(s) { Iterator iter = getObservers(s).iterator(); while ( iter.hasNext() ) updateObserver(s, ((Observer)iter.next())); } Advice … public void addObserver(Subject s,Observer o){ getObservers(s).add(o); } public void removeObserver(Subject s,Observer o){ getObservers(s).remove(o); } abstract protected void updateObserver(Subject s, Observer o); abstract protected pointcut subjectChange(Subject s); after(Subject s) : subjectChange(s) { Iterator iter = getObservers(s).iterator(); while ( iter.hasNext() ) updateObserver(s, ((Observer)iter.next())); }
14
public aspect ColorObserver extends ObserverProtocol{ declare parents: Point implements Subject; declare parents: Line implements Subject; declare parents: Screen implements Observer; protected pointcut subjectChange(Subject s) : ( call ( void Point.setColor(Color)) || call ( void Line.setColor(Color)) ) && target(s); protected void updateObserver(Subject s, Observer o) { ((Screen)o).display("Color change."); } observer pattern The observer pattern 4 public aspect ColorObserver extends ObserverProtocol{ declare parents: Point implements Subject; declare parents: Line implements Subject; declare parents: Screen implements Observer; protected pointcut subjectChange(Subject s) : ( call ( void Point.setColor(Color)) || call ( void Line.setColor(Color)) ) && target(s); protected void updateObserver(Subject s, Observer o) { ((Screen)o).display("Color change."); } Mark Base Classes public aspect ColorObserver extends ObserverProtocol{ declare parents: Point implements Subject; declare parents: Line implements Subject; declare parents: Screen implements Observer; protected pointcut subjectChange(Subject s) : ( call ( void Point.setColor(Color)) || call ( void Line.setColor(Color)) ) && target(s); protected void updateObserver(Subject s, Observer o) { ((Screen)o).display("Color change."); } Pointcuts Impl. public aspect ColorObserver extends ObserverProtocol{ declare parents: Point implements Subject; declare parents: Line implements Subject; declare parents: Screen implements Observer; protected pointcut subjectChange(Subject s) : ( call ( void Point.setColor(Color)) || call ( void Line.setColor(Color)) ) && target(s); protected void updateObserver(Subject s, Observer o) { ((Screen)o).display("Color change."); } Aspect Impl. public aspect ColorObserver extends ObserverProtocol{ declare parents: Point implements Subject; declare parents: Line implements Subject; declare parents: Screen implements Observer; protected pointcut subjectChange(Subject s) : ( call ( void Point.setColor(Color)) || call ( void Line.setColor(Color)) ) && target(s); protected void updateObserver(Subject s, Observer o) { ((Screen)o).display("Color change."); } Update Impl.
15
observer pattern The observer pattern 5 Two primary advantages: 1.Reusability Implementationbinding Implementation is separated from binding Implementation is reusable. 2.Independent Extensibility Subject can be mapped to many classes. A class can be assigned many roles. The same role can be assigned to the same class in different bindings.
16
Lack of Support for: Multiabstraction Aspects No separation of concerns in the aspect: –Contains all methods of all abstractions defined in it. Contradicts OOP and AOP. –Fields and inheritance for the abstractions? AspectJ’s introduction mechanism leads to losing independent extensibility. No dynamic dispatch.
17
Lack of support for: Sophisticated Mapping Each abstraction must be mapped directly to some base class. This is not always the case: –Consider a graph aspect, defined in terms of Node and Edge. –An application in which every Point has a collection of adjacent points. –Edge cannot be mapped to any base class.
18
ObserverProtocol ColorObserver Software Lack of support for: Reusable Aspect Bindings Every aspect binding is coupled to one particular aspect implementation. LocationObserver ColorObserver 1 ColorObserver 2 ObserverProtocol Software
19
Lack of support for: Aspectual Polymorphism Once the aspect is compiled together with the target package, the changes in the execution are determined. It is not possible to determine at runtime which implementation of the aspect to apply.
20
The Caesar Model 1 ACIACI - Aspect Collaboration Interface: An interface definition for aspects with multiple mutually recursive nested types An interface definition for aspects with multiple mutually recursive nested types. implementationsbindingsThe purpose of ACI: decoupling aspect implementations and aspect bindings. The modules are independently defined, but are indirectly connected.
21
The Caesar Model 2 A Software System … Observer Subject Observer ACI Observer Subject Color Observer
22
Aspect Collaboration Interfaces 1 interface ObserverProtocol { interface Subject { provided void addObserver(Observer o); provided void removeObserver(Observer o); provided void changed(); expected String getState(); } interface Observer { expected void notify(Subject s); } Nested Subject Interface interface ObserverProtocol { interface Subject { provided void addObserver(Observer o); provided void removeObserver(Observer o); provided void changed(); expected String getState(); } interface Observer { expected void notify(Subject s); } Expected Method interface ObserverProtocol { interface Subject { provided void addObserver(Observer o); provided void removeObserver(Observer o); provided void changed(); expected String getState(); } interface Observer { expected void notify(Subject s); } Provided Methods interface ObserverProtocol { interface Subject { provided void addObserver(Observer o); provided void removeObserver(Observer o); provided void changed(); expected String getState(); } interface Observer { expected void notify(Subject s); } Nested Observer Interface interface ObserverProtocol { interface Subject { provided void addObserver(Observer o); provided void removeObserver(Observer o); provided void changed(); expected String getState(); } interface Observer { expected void notify(Subject s); } Abstract Observer Aspect interface ObserverProtocol { interface Subject { provided void addObserver(Observer o); provided void removeObserver(Observer o); provided void changed(); expected String getState(); } interface Observer { expected void notify(Subject s); }
23
The ObserverProtocol ACI has 2 nested, mutually recursive, ACIs. Determines impl./bindings relations: –provided: what the aspect should provide. –expected: required from the binding. The provided & expected facets are implemented in different modules. However, They are indirectly connected through the ACI. Aspect Collaboration Interfaces 2
24
What do we gain? 1.An abstract aspect. 2.Aspect-related Interfaces that are “aware” of each other and can collaborate. 3.A modularization of the problem. 4.No binding-specific members. Aspect Collaboration Interfaces 3
25
Aspect Implementations 1 providedAn aspect implementation must implement all the provided methods. The implementation class structure is the same as of the ACI structure. provided expectedThe implementation of the provided methods can call the expected methods.
26
class ObserverProtocolImpl implements ObserverProtocol { class Subject { List observers = new LinkedList(); void addObserver(Observer o) { observers.add(o);} void removeObserver(Observer o) { observers.remove(o); } void changed() { Iterator iter = observers.iterator(); while ( iter.hasNext() ) ((Observer)iter.next()).notify(this); } Provided Methods class ObserverProtocolImpl implements ObserverProtocol { class Subject { List observers = new LinkedList(); void addObserver(Observer o) { observers.add(o);} void removeObserver(Observer o) { observers.remove(o); } void changed() { Iterator iter = observers.iterator(); while ( iter.hasNext() ) ((Observer)iter.next()).notify(this); } A Nested Class class ObserverProtocolImpl implements ObserverProtocol { class Subject { List observers = new LinkedList(); void addObserver(Observer o) { observers.add(o);} void removeObserver(Observer o) { observers.remove(o); } void changed() { Iterator iter = observers.iterator(); while ( iter.hasNext() ) ((Observer)iter.next()).notify(this); } Observer Aspect class ObserverProtocolImpl implements ObserverProtocol { class Subject { List observers = new LinkedList(); void addObserver(Observer o) { observers.add(o);} void removeObserver(Observer o) { observers.remove(o); } void changed() { Iterator iter = observers.iterator(); while ( iter.hasNext() ) ((Observer)iter.next()).notify(this); } Aspect Implementations 2
27
What do we gain? Observeraspects 1.Many kinds of Observer aspects, with a common interface. 2.A modularization of the aspect. 3.No need for “global” members. 4.Still no binding-specific members. Aspect Implementations 3
28
Aspect Bindings 1 expectedAn aspect binding implements all the expected methods in the ACI. For each nested ACI there may be zero,one, or more nested bindings. wrappersBase objects are accessed through wrappers.
29
Aspect Bindings 2 class ColorObserver binds ObserverProtocol { class PointSubject binds Subject wraps Point { String getState() { return "Point colored "+wrappee.getColor()}} } class LineSubject binds Subject wraps Line { String getState() { return "Line colored "+wrappee.getColor(); } } class ScreenObserver binds Observer wraps Screen { void notify(Subject s) {wrappee.display("Color changed: "+s.getState());} } after(Point p): (call(void p.setColor(Color))){ PointSubject(p).changed(); } after(Line l): (call(void l.setColor(Color))){ LineSubject(l).changed(); } } Advices class ColorObserver binds ObserverProtocol { class PointSubject binds Subject wraps Point { String getState() { return "Point colored "+wrappee.getColor()}} } class LineSubject binds Subject wraps Line { String getState() { return "Line colored "+wrappee.getColor(); } } class ScreenObserver binds Observer wraps Screen { void notify(Subject s) {wrappee.display("Color changed: "+s.getState());} } after(Point p): (call(void p.setColor(Color))){ PointSubject(p).changed(); } after(Line l): (call(void l.setColor(Color))){ LineSubject(l).changed(); } } A “ Binding ” class ColorObserver binds ObserverProtocol { class PointSubject binds Subject wraps Point { String getState() { return "Point colored "+wrappee.getColor()}} } class LineSubject binds Subject wraps Line { String getState() { return "Line colored "+wrappee.getColor(); } } class ScreenObserver binds Observer wraps Screen { void notify(Subject s) {wrappee.display("Color changed: "+s.getState());} } after(Point p): (call(void p.setColor(Color))){ PointSubject(p).changed(); } after(Line l): (call(void l.setColor(Color))){ LineSubject(l).changed(); } } Binding of Observer class ColorObserver binds ObserverProtocol { class PointSubject binds Subject wraps Point { String getState() { return "Point colored "+wrappee.getColor()}} } class LineSubject binds Subject wraps Line { String getState() { return "Line colored "+wrappee.getColor(); } } class ScreenObserver binds Observer wraps Screen { void notify(Subject s) {wrappee.display("Color changed: "+s.getState());} } after(Point p): (call(void p.setColor(Color))){ PointSubject(p).changed(); } after(Line l): (call(void l.setColor(Color))){ LineSubject(l).changed(); } } Binding of Subject class ColorObserver binds ObserverProtocol { class PointSubject binds Subject wraps Point { String getState() { return "Point colored "+wrappee.getColor()}} } class LineSubject binds Subject wraps Line { String getState() { return "Line colored "+wrappee.getColor(); } } class ScreenObserver binds Observer wraps Screen { void notify(Subject s) {wrappee.display("Color changed: "+s.getState());} } after(Point p): (call(void p.setColor(Color))){ PointSubject(p).changed(); } after(Line l): (call(void l.setColor(Color))){ LineSubject(l).changed(); } }
30
What do we gain? 1.Interface can be bound in many ways. 2.A “Binding” is a module. 3.No need for “global” members. 4.No aspect-implementation specific details. Aspect Bindings 3
31
Wrapper Recycling Avoiding multiple wrappers for the same base object. Access to a base object is done through the wrapper: outerClassInstance.Wrapper(constructor_args) A wrapper may wrap a set of objects.
32
Most Specific Wrappers 1 A mechanism that determines the most specific wrapper for an object based on the object’s runtime type, when multiple nested binding classes with the same name are available.
33
Most Specific Wrappers 2 class MovableFigures { class MovableFigure implements Movable wraps Figure { void moveBy(int x, int y) {}; } class MovableFigure implements Movable wraps Point { void moveBy(int x, int y) { wrappee.setX(wrappee.getX()+x); wrappee.setY(wrappee.getY()+y); } class MovableFigure implements Movable wraps Line { void moveBy(int x, int y) { MovableFigure(wrappee.getP1()).moveBy(x,y); MovableFigure(wrappee.getP2()).moveBy(x,y); }
34
Most Specific Wrappers 3 class Test { MovableFigures mv = new MovableFigures(); void move(Figure f) { mv.MovableFigure(f).moveBy(5,7); } On a constructor/wrapper call, the dynamic type of the argument determines the actual nested binding to instantiate/recycle.
35
Pointcuts and Advices Supported similarly to AspectJ Part of the modular ACIs. A binding must be explicitly deployed. The difference: Compilation with pointcuts and advices does not change the base class semantics Compilation with pointcuts and advices does not change the base class semantics.
36
Weavelets and Deployment Weavelet: a composition of an implementation and a binding. A weavelet has to be deployed in order to activate its pointcuts and advices. class CO extends ObserverProtocol {};
37
Weavelets 2 What do we gain? Reusable aspect bindings. Reusable aspect implementations. class CO1 extends ObserverProtocol {}; class CO2 extends ObserverProtocol {}; class CO3 extends ObserverProtocol {}; class Obs1 extends ObserverProtocol {}; class Obs2 extends ObserverProtocol {}; class Obs3 extends ObserverProtocol {};
38
Static Deployment 1 Pointcuts and advices of co weavelet are engaged only if it is deployed. Deployment takes place at loading time of Test. class Test... { deploy deploy public static final CO co = new CO();... }
39
Static Deployment 2 Weavelet access. Objects are accessed through the wrappers mechanism. class Test{ deploy deploy public static final CO co = new CO(); void register(Point p, Screen s){ co.PointSubject(p).addObserver( co.ScreenObserver(s) ); }
40
Dynamic Deployment 1 It is possible to decide dynamically which aspect implementation to deploy. class Logging { after(): (call(void Point.setX(int)) || call(void Point.setY(int)) ) { System.out.println("Coordinates changed"); } class VerboseLogging extends Logging { after(): (call(void Point.setColor(Color)) { System.out.println("Color changed"); }
41
Dynamic Deployment 2 class Main { public static void main(String args[]) { Logging log = null; Point p[] = createSamplePoints(); if (args[0].equals("-log")) log = new Logging(); else if (args[0].equals("-verbose")) log = new VerboseLogging(); deploy (l) { modify(p); } } public static void modify(Point p[]) { p[3].setX(5); p[2].setColor(Color.RED); } What is the type of log ? class Main { public static void main(String args[]) { Logging log = null; Point p[] = createSamplePoints(); if (args[0].equals("-log")) log = new Logging(); else if (args[0].equals("-verbose")) log = new VerboseLogging(); log = new VerboseLogging(); deploy (l) { modify(p); } } public static void modify(Point p[]) { p[3].setX(5); p[2].setColor(Color.RED); }
42
Virtual Classes and Static Typing All nested interfaces of a CI and all classes that implement or bind such interfaces, are virtual types/classes Compatible with Java’s approach.
43
Caesar vs. Hyper/J hyperslices hypermoduleHyper/J: Independent hyperslices, integrated by composition rules (hypermodule). Class-based. Can’t change individual objects. Lacks CI’s and reusable bindings: either the modules are independent, or composition becomes very complex. Composition language is not OO enough.
44
Caesar vs. Composition Filters CFs: filters for object’s in/out messages. Integration through join points. CF have no mechanism for separating aspect implementation from aspect bindings. No aspectual polymorphism. CFs are more declarative: good for some kinds of concerns.
45
Current Status in caesarj.org “Very active on-going research”. The AORTA project. Industry: in www.topprax.de –Applying aspect-oriented programming in commercial software development
46
Conclusions JPI alone does not suffice for a modular structuring of aspects, resulting in tangled aspect code. Caesar enables: –Componentization of aspects. –Reusability of aspects bindings & implementations. –Polymorphic aspects usage. –Dynamic aspect deployment. Caesar is based on the notion of an ACI ACIs can be applied to support a more modular structuring of aspect code and better aspect reuse.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.