AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

52
AspectJ programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski

Transcript of AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Page 1: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

AspectJTM programming techniques and use in Eclipse

AOSD Seminar

presented by

Hagai Cibulski

Page 2: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Agenda

1. Examples of using AspectJ for solving real-world problems

2. AspectJ/Eclipse integration

Page 3: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Part 1: Problem Solving Examples

Design by contract. Flexible access control. Persistence and Dirty Tracking. Resource-pool management. Policy Enforcement. Semantic based crosscutting behavior.

Page 4: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 5: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Contract Enforcement - Example

class Point {int _x, _y;void setX(int x) { _x = x; } // precondition: x >= MIN_Xvoid 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 }}

Page 6: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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);

}private void assert(boolean v) {

if ( !v ) throw new RuntimeException();

}}

Page 7: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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();

}}

Page 8: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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!

Page 9: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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!

Page 10: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 11: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 12: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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);};

Page 13: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Persistence:Data Access Sequence

Business Object

DataAccessObject

Data StoreValue Object

create

getdata fetchdata

create

setproperty

setproperty

setdatagetproperty

getproperty

storedata

Page 14: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Dirty Tracking Persistent Objects

DAO setData() stores the ValueObject.

Let’s store ValueObject only if it’s dirty.

Intercept ADO.setData().

Page 15: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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

Page 16: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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

Page 17: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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 startJoin points

Page 18: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Resource-pool managementA 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

Page 19: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

public aspect ThreadPooling {

Stack pool = new Stack();

pointcut threadCreation(Runnable runnable)         : call(Thread.new(Runnable)) && args(runnable);

Page 20: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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 managementThread Pooling Aspect

Can You see the problem here?

Page 21: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Resource-pool managementThread 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) {}    }   }   }

Page 22: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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 managementThread 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.

Page 23: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 24: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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…

Page 25: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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 EnforcementBase aspect: EventListenerManagement

Page 26: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Policy EnforcementUniqueness 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); }

Page 27: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Policy EnforcementImplementing 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.

Page 28: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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 EnforcementNo loitering-views concern

Abstract method

Page 29: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Policy EnforcementImplementing 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?

Page 30: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 31: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 32: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 33: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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

Page 34: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

End of part 1-- Problem Solving Examples

Questions?

Page 35: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 36: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Part 2: AspectJ/Eclipse Integration

AJDT. Caching example. Build configurations. Aspect visualization. Debugging. Generating documentation.

Page 37: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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

Page 38: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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; }}

Page 39: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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?

Page 40: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Cache Example – Aspect viewOutline 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.

Page 41: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Cache Example – Aspected classOutline 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.

Page 42: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 43: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Build configurationsHow 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.

Page 44: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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

Page 45: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 46: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Aspect Visualization – The big picture

Page 47: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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 whatyour Debug aspect is affecting?Deselect all but the Debug aspect!

Page 48: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Debugging You can set breakpoints in before and after advice.

Page 49: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

Debugging When reaching the breakpoint, the advice is correctly

displayed on the stack.

Page 50: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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.

Page 51: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

End of part 2-- Eclipse integration

Questions?

Page 52: AspectJ TM programming techniques and use in Eclipse AOSD Seminar presented by Hagai Cibulski.

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/