Download presentation
Presentation is loading. Please wait.
Published byKerry Webster Modified over 9 years ago
1
AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski
2
Agenda 1. Examples of using AspectJ for solving real-world problems 2. AspectJ/Eclipse integration
3
Part 1: Problem Solving Examples Design by contract. Flexible access control. Persistence and Dirty Tracking. Resource-pool management. Policy Enforcement. Semantic based crosscutting behavior.
4
Contract Enforcement Design by contract. Precondition defines the client's responsibility. Postcondition is the supplier's part of the contract. Putting pre- and post-condition assertions directly into application code? Lack of code modularity. Tangled code. Mixes business-logic code with assertions.
5
Contract Enforcement - Example class Point { int _x, _y; void setX(int x) { _x = x; } // precondition: x >= MIN_X void setY(int y) { _y = y; } int getX() { return _x; } int getY() { return _y; } } class Client { Client(Point p) { p.setX(-1); p.setY(50);// postcondition: p.getY() == 50 }
6
Pre-Condition Using Before Advice aspect PointBoundsPreCondition { before(int newX):call(void Point.setX(int)) && args(newX) { assert(newX >= MIN_X); assert(newX <= MAX_X); } before(int newY): call(void Point.setY(int)) && args(newY){ assert(newY >= MIN_Y); assert(newY <= MAX_Y); } private void assert(boolean v) { if ( !v ) throw new RuntimeException(); } }
7
Post-Condition Using After Advice aspect PointBoundsPostCondition { after(Point p, int newX) returning: call(void Point.setX(int)) && target(p) && args(newX) { assert(p.getX() == newX); } after(Point p, int newY) returning: call(void Point.setY(int)) && target(p) && args(newY) { assert(p.getY() == newY); } private void assert(boolean v) { if ( !v ) throw new RuntimeException(); }
8
Flexible Access Control Enforce an access-control crosscutting concern. Java's access controls: public, private, package, and protected. Not enough control in many cases. Example: Factory design-pattern implementation: We want only the factory to create the product objects. Other classes should be prohibited from accessing constructors of any product class. Marking constructors with package access? Only when the factory resides in the same package as the manufactured classes - inflexible solution!
9
Flexible Access Control (continued) C++'s friend mechanism controls access to a class from other specified classes and methods. With AspectJ we can implement such functionality in Java. Even more fine-grained and expressive access control!
10
Flexible Access Control - Example Product class has a constructor and a configure() method. We also declare a nested FlagAccessViolation aspect. Pointcut 1 detects constructor calls not from ProductFactory or its subclasses. Pointcut 2 detects configure() calls not from ProductConfigurator or its subclasses. We declare either such violations as compile-time errors. public class Product { public Product() { /* constructor implementation */ } public void configure() { /* configuration implementation */ } static aspect FlagAccessViolation { pointcut factoryAccessViolation() : call(Product.new(..)) && !within(ProductFactory+); pointcut configuratorAccessViolation() : call(* Product.configure(..)) && !within(ProductConfigurator+); declare error : factoryAccessViolation() || configuratorAccessViolation() : "Access control violation"; } } must be a “static pointcut” If any of the join points in the pointcut possibly exist in the program, the compiler should emit an error of String.
11
Flexible Access Control - Example public class ProductFactory { public Product createProduct() { return new Product(); // ok } public void configureProduct(Product product) { product.configure(); // error } } The ProductFactory class calls the Product.configure() method. Compile-time error with a specified "Access control violation" message.
12
Persistent Objects A ValueObject represents a persistent entity. A Data Access Object (DAO) accesses the actual Data Store. DAO getData() and setData() loads and stores the ValueObject. Interfaces implemented in persistence layer: interface ValueObject {}; interface DAO { public ValueObject getData(); public void setData(ValueObject v); };
13
Persistence: Data Access Sequence Business Object Data Access Object Data Store Value Object create getdata fetchdata create setproperty setdata getproperty storedata
14
Dirty Tracking Persistent Objects DAO setData() stores the ValueObject. Let’s store ValueObject only if it’s dirty. Intercept ADO.setData().
15
aspect DirtyTracking { public boolean ValueObject.dirty = false; pointcut dirtyingAction(ValueObject v) : set(* *) && target(v) && !within(DirtyTracking); after(ValueObject v) returning : execution(*.new(..)) && this(v) { v.dirty = false; } after(ValueObject v) returning : dirtyingAction(v) { v.dirty = true; } void around(ValueObject v) : execution(void *.setData(ValueObject)) && this(DAO) && args(v) { if (v.dirty) // Let’s store ValueObject only if it ’ s dirty { proceed(v); v.dirty = false; } Dirty Tracking - Implementation
16
Resource-pool management Optimize resource usage, by recycling previously created resources. Threads. Database connections. But in what phase of development? Up front design of when and how to obtain resources from the pool and how to put them back. Over design? Complicated system! Optimization after profiling. Under design? Many modifications! The architect ’ s dilemma
17
Resource-pool management example: A multi-threaded server /** a simple TCP/IP service for converting requested strings to uppercase. */ public class UppercaseServer { public static void main(String[] args) throws Exception { int portNum = Integer.parseInt(args[0]); ServerSocket serverSocket = new ServerSocket(portNum); while (true) { Socket requestSocket = serverSocket.accept(); /* The server creates a new thread each time a new connection request arrives. */ Thread serverThread = new Thread( new UppercaseWorker(requestSocket)); serverThread.start(); } Thread creation Thread start Join points
18
Resource-pool management A worker thread class UppercaseWorker implements Runnable { private Socket _requestSocket; public UppercaseWorker(Socket requestSocket) throws IOException { _requestSocket = requestSocket; } public void run() { BufferedReader requestReader = null; Writer responseWriter = null; try { requestReader = new BufferedReader( new InputStreamReader(_requestSocket.getInputStream())); responseWriter = new OutputStreamWriter( _requestSocket.getOutputStream()); while (true) { String requestString = requestReader.readLine(); if (requestString == null) break; responseWriter.write(requestString.toUpperCase() + "\n"); responseWriter.flush(); } } catch(IOException ex) {} finally {/* cleanup */} } /* Once a thread completes serving a connection, it terminates. */ Session Join point
19
Resource-pool management Thread Pooling Aspect ThreadPooling aspect adds thread pooling to the server. The thread pool is implemented as a stack. We intercept the creation of new thread objects. public aspect ThreadPooling { Stack pool = new Stack(); pointcut threadCreation(Runnable runnable) : call(Thread.new(Runnable)) && args(runnable);
20
Advise the threadCreation() pointcut to first check the thread pool for available threads. If a thread is available, reuse it. If no thread is available, create a new Thread. Thread around(Runnable runnable) : threadCreation(runnable) { Thread availableThread = null; if (pool.empty()) availableThread = new Thread(); else availableThread = (Thread)pool.pop(); availableThread.setRunnable(runnable); return availableThread; } Resource-pool management Thread Pooling Aspect Can You see the problem here?
21
Resource-pool management Thread Pooling Aspect Pointcut session () captures the run () method's execution of any Thread objects. pointcut session(Thread thread) : execution(void Thread.run()) && this(thread); Putting session() inside a while(true) loop, advises session() to never finish servicing. The result: A thread, once created, never dies. Once a request is processed, put the thread back into the pool in a waiting state. void around(Thread thread) : session(thread) { while (true) { proceed(thread); pool.push(thread); synchronized(thread) { try { thread.wait(); } catch(InterruptedException ex) {} } } }
22
Pointcut threadStart() captures a call to Thread.start() pointcut threadStart(Thread thread) : call(void Thread.start()) && target(thread); void around(Thread thread) : threadStart(thread) { if (thread.isAlive()) { // wake it up synchronized(thread) { thread.notifyAll(); } } else { proceed(thread); } } Resource-pool management Thread Pooling Aspect isAlive() checks if the thread previously started: Thread obtained from a pool, now in a waiting state. Wake up the thread by notifying it. If the thread has not started yet: Freshly created thread. proceed with starting the thread.
23
Resource-pool management Database Connections Same technique. Capture joinpoints that create new connections. Advise them to use one from a connection pool instead, if available. Capture joinpoints that close connections. Advise them to put those objects back in the pool.
24
Policy Enforcement Swing MVC pattern includes unenforced assumptions: Models let you add a listener object more than once. Duplicate work if an event-notification method carries an expensive operation. Forgetting to remove listeners before destroying a view. Memory leak! Let’s enforce a policy to ensure no duplicate listener objects, and listeners do not loiter around. To implement policy enforcement using OOP, you must use a combination of documentation, code reviews, and so on …
25
Both concerns requires capturing joinpoints that add listeners to models. Share the code via a base abstract EventListenerManagement aspect. addListenerCall() pointcut captures calls to methods adding a listener. call(void *.add*Listener( EventListener +)) declare precedence : EventListenerWeakening, EventListenerUniqueness; Policy Enforcement Base aspect: EventListenerManagement
26
Policy Enforcement Uniqueness concern Abstract method Problem: Models let you add a listener object more than once. Duplicate notification. Solution: Before adding a listener, check whether it was previously added. If that listener is already present, the operation does not proceed. Otherwise, add the listener. EventListenerUniqueness aspect extends EventListenerManagement and ensures no duplicate listener objects in a model. void around(...) : addListenerCall(model, listener) { EventListener[] listeners = getCurrentListeners(model); if (! Utils.isInArray(listeners, listener)) proceed(model, listener); }
27
Policy Enforcement Implementing Uniqueness concern for tables and lists The concrete aspect TableModelListenerUniqueness extends EventListenerUniqueness to apply the aspect to TableModel. Another concrete aspect, ListDataListenerUniqueness, does the same for list- related classes.
28
Problem: Forgetting to remove listeners before destroying a view. Memory leak! Solution: Instead of adding a listener to a model directly, wrap it as a referent in a WeakReference object and add it. void around(Object model, EventListener listener) : addListenerCall(model, listener) { proceed(model, getWeakListener(listener)); } Policy Enforcement No loitering-views concern Abstract method
29
Policy Enforcement Implementing a no loitering-views concern The RemoveGarbageCollectedListeners aspect removes WeakEventListener from the model when it detects that the referent is garbage collected. abstract static aspect RemoveGarbageCollectedListeners { pointcut eventNotification(WeakEventListener weakListener, EventObject event) : execution(void WeakEventListener+.*(EventObject+)) && this(weakListener) && args(event) && lexicalScopeMatch(); abstract pointcut lexicalScopeMatch(); public abstract void removeListener(EventObject event, EventListener listener); void around(WeakEventListener weakListener, EventObject event) : eventNotification(weakListener, event) { if (weakListener.getDelegatee() != null) { proceed(weakListener, event); } else { removeListener(event, weakListener); } } } We check the collected referent in an event notification method. Can You see the problem with this?
30
Semantic based crosscutting behavior Problem: Operations with the same semantic characteristics should typically implement common behaviors. A wait cursor should be put before any slow method executes. Authentication before access to all security-critical data. Since such concerns possess a crosscutting nature, AOP and AspectJ offer mechanisms to modularize them. Because a method's name might not indicate its characteristics, we need a different mechanism to capture such methods.
31
Semantic based crosscutting behavior Solution: Declare the aspect adding semantic-based crosscutting behavior as an abstract aspect. In that aspect, declare an abstract pointcut for methods with characteristics under consideration. Finally, write an advice performing the required implementation.
32
Semantic based crosscutting behavior Example: SlowMethodAspect declares the abstract slowMethods() pointcut and advises it to first put a wait cursor, proceed with the original operation, and finally restore the original cursor.
33
Semantic based crosscutting behavior Implementation: public abstract aspect SlowMethodAspect { abstract pointcut slowMethods(Component uiComp); void around(Component uiComp) : slowMethods(uiComp) { Cursor originalCursor = uiComp.getCursor(); Cursor waitCursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); uiComp.setCursor(waitCursor); try { proceed(uiComp); } finally { uiComp.setCursor(originalCursor); } } } GUIComp1 contains following aspect: public static aspect SlowMethodsParticipant extends SlowMethodAspect { pointcut slowMethods(Component uiComp) : execution(void GUIComp1.performOperation1()) && this(uiComp); } The aspected classes include code to participate in the collaboration
34
End of part 1 -- Problem Solving Examples Questions?
35
Part 2: Eclipse Integration To encourage the growth of the AspectJ technology and community, PARC transferred AspectJ to an openly-developed eclipse.org project in December of 2002.
36
Part 2: AspectJ/Eclipse Integration AJDT. Caching example. Build configurations. Aspect visualization. Debugging. Generating documentation.
37
AJDT AJDT ( AspectJ Development Tools) AspectJ plugin for Eclipse. at http://www.eclipse.org/ajdt http://www.eclipse.org/ajdt Consistent with JDT (Java Development Tools) AspectJ plugin for Java. Installing the latest AJDT for Eclipse 3.0: You install AJDT From Eclipse. Help>Software Updates>Find and Install... And so on. http://www-106.ibm.com/developerworks/library/j-ajdt/ First steps: File>New>AspectJ Project File>New>Aspect Just the same as if the project were a Java project
38
Example – a long calculation (we would like to cache the result) How many seconds does it take for running this Java application? package caching; public class Application { public static void main(String[] args) { System.out.println("The square of 45 is " + calculateSquare(45)); System.out.println("The square of 64 is " + calculateSquare(64)); System.out.println("The square of 45 is " + calculateSquare(45)); System.out.println("The square of 64 is " + calculateSquare (64)); } private static int calculateSquare(int number) { try {Thread.sleep(7000);} catch (InterruptedException ie) {} return number * number; }
39
Example – Cache aspect Now, We press File>New>Aspect and type the following aspect: import java.util.Hashtable; public aspect Cache { private Hashtable valueCache = new Hashtable(); pointcut calculate(int i) : args(i) && (execution(int Application.calculateSquare(int))); int around(int i) : calculate(i) { if (valueCache.containsKey(new Integer(i))) { return ((Integer) valueCache.get(new Integer(i))).intValue(); } int square = proceed(i); valueCache.put(new Integer(i), new Integer(square)); return square; } Now, How many seconds does it take?
40
Cache Example – Aspect view Outline view of the Cache aspect: around advice node > "advises" node > method node. The outline shows the relationship this construct (the around advice) has with another construct in the system - the method being advised. The target of the relationship is a hyperlink. click on the Application.calculateSquare(int) node, and the editor will switch to it.
41
Cache Example – Aspected class Outline view of Application class calculateSquare() method node > "advised by" node > source of advice in this case, the around advice in the Cache aspect The source of the relationship is a hyperlink.
42
Cache Example – Advised by menu Marker shows advice. Right-click on it. Popup menu appears. See Advised by menu. See appropriate advice. Select advice to open it.
43
Build configurations How do we selectively add and remove aspects from an application? Build configurations define the source files that are passed to the compiler. To exclude an aspect, right-click on it and select Exclude. The icon for Debug.java is hollowed out, indicating its exclusion. The icon for the spacewar package is partially emptied out, to indicate that some, but not all, of the package has been excluded. To include an aspect, right-click on it and select Include. The icons will now fill in, and the project will be built to include this aspect. Run the program, and you'll see a window, with debugging information.
44
Build configurations (continued) Build configurations are stored in.ajproperties files. In the Package Explorer below, one configuration has a triangle in it, which indicates that it is the active configuration. Any changes made to the configuration using the Include and Exclude contextual menu options are written to the currently active configuration file. Active configuration
45
Aspect Visualization Perspective Window>Open Perspective... Aspect Visualization Gives an overall feeling for how your application behaves. How many classes do your aspects affect? View the crosscutting concerns in your application. The Visualiser is located in the center of the perspective. It represents the classes and aspects within a project as bars and the places where aspects affect your code as stripes on those bars. The lengths of the bars are relative to file size.
46
Aspect Visualization – The big picture
47
Visualizing the effects of the debug aspect The stripe colors match those on the buttons in the Visualiser menu. Next to each of the colored buttons is a checkbox and a label. The label gives the name of the aspect that the color represents. The checkbox indicates if this aspect is included in the current visualization. You can filter out any aspects you're not interested in. Just want to see what your Debug aspect is affecting? Deselect all but the Debug aspect!
48
Debugging You can set breakpoints in before and after advice.
49
Debugging When reaching the breakpoint, the advice is correctly displayed on the stack.
50
Generating documentation The javadoc tool Generates API documentation for Java projects, based on specially formatted comments in the source code. The ajdoc tool is AspectJ extension to javadoc. Adds details of the crosscutting nature of your aspects. The javadoc output has been enhanced to show where the advice takes effect.
51
End of part 2 -- Eclipse integration Questions?
52
References 1. Laddad, R. I Want my AOP, part 3. http://www.javaworld.com/javaworld/jw-04-2002/jw-0412-aspect3.html 2. Coyler, A. AspectJ. In Aspect-Oriented Software Development, R. Filman et al., Chapter 6. 3. AspectJ documentation. http://eclipse.org/aspectj 4. Chapman, M., and Hawkins, H. Develop aspect-oriented Java applications with Eclipse and AJDT. http://www-106.ibm.com/developerworks/library/j-ajdt/
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.