1 / 52

AspectJ TM programming techniques and use in Eclipse

AspectJ TM programming techniques and use in Eclipse. AOSD Seminar presented by Hagai Cibulski. Agenda. Examples of using AspectJ for solving real-world problems AspectJ/Eclipse integration. Part 1: Problem Solving Examples. Design by contract. Flexible access control.

helena
Télécharger la présentation

AspectJ TM programming techniques and use in Eclipse

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. AspectJTM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski

  2. Agenda • Examples of using AspectJ for solving real-world problems • 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. 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. Contract Enforcement

  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-ConditionUsing 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); } privatevoid assert(boolean v) { if ( !v ) throw new RuntimeException(); } }

  7. Post-ConditionUsing 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 theprogram, 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. Business Object Data AccessObject Data Store Value Object create getdata fetchdata create setproperty setproperty setdata getproperty getproperty storedata Persistence:Data Access Sequence

  14. Dirty Tracking Persistent Objects • DAO setData() stores the ValueObject. • Let’s store ValueObject only if it’s dirty. • Intercept ADO.setData().

  15. Dirty Tracking - Implementation 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; } } }

  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. */ publicclass UppercaseServer {public static void main(String[] args) throws Exception {int portNum = Integer.parseInt(args[0]);    ServerSocket serverSocket = new ServerSocket(portNum); while (true) { SocketrequestSocket = 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 managementThread 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. publicaspect ThreadPooling { Stack pool = new Stack(); pointcutthreadCreation(Runnable runnable)         : call(Thread.new(Runnable)) && args(runnable);

  20. Resource-pool managementThread Pooling Aspect • 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;} Can You see the problem here?

  21. Resource-pool managementThread Pooling Aspect • Pointcut session() captures the run() method's execution of any Thread objects. pointcutsession(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. voidaround(Thread thread) : session(thread) {while (true) {proceed(thread);            pool.push(thread);synchronized(thread) {try {                    thread.wait();                } catch(InterruptedException ex) {}    }   }   }

  22. Resource-pool managementThread Pooling Aspect • Pointcut threadStart() captures a call to Thread.start() • pointcutthreadStart(Thread thread)         : call(void Thread.start()) && target(thread);voidaround(Thread thread) : threadStart(thread) {if (thread.isAlive()) {     // wake it upsynchronized(thread) {         thread.notifyAll();}    } else {proceed(thread);    }} 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 managementDatabase 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. Policy Enforcement Base aspect: EventListenerManagement • 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;

  26. Policy Enforcement Uniquenessconcern 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. • voidaround(. . .) : addListenerCall(model, listener) { EventListener[] listeners = getCurrentListeners(model);if (! Utils.isInArray(listeners, listener))             proceed(model, listener);} Abstract method

  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. Policy Enforcement No loitering-views concern 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. voidaround(Object model, EventListener listener)         : addListenerCall(model, listener) {proceed(model, getWeakListener(listener));    } 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. abstractstaticaspectRemoveGarbageCollectedListeners {pointcut eventNotification(WeakEventListener weakListener,                                   EventObject event)             : execution(void WeakEventListener+.*(EventObject+))            && this(weakListener) && args(event)             && lexicalScopeMatch();abstractpointcutlexicalScopeMatch();publicabstractvoid removeListener(EventObject event,                                             EventListener listener);voidaround(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 • 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. 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. 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.

  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.

More Related