Introduction

Aspect-oriented programming helps programmers in the separation of (cross-cutting) concerns to improve the overall architecture of an application by making it more modular and removing duplicate code.

Archive for the ‘AOP’ Category

Friday, August 19th, 2005

As2lib 0.9.2, Released!

We have just released a new version of the as2lib - Open Source ActionScript 2.0 Library - 0.9.2.

Highlight of this release is the revised Aspect Oriented Programming (AOP) framework.

  • WithinPointcut - Capture join points based on their lexical-structure.
  • NotPointcut - Capture pointcuts based on characteristics they are not allowed to have.
  • ’super’ - Advised join points can use ’super’ now.
  • And of course a lot of bug fixes were made.

All Features at a Glance

  • Event Handling - org.as2lib.env.event
  • Exception Handling - org.as2lib.env.except
  • Logging - org.as2lib.env.log
  • Overloading - org.as2lib.env.overload
  • Reflections - org.as2lib.env.reflect
  • Aspect Oriented Programming (AOP) - org.as2lib.aop
  • Data Holders/Structures and Iterators - org.as2lib.data.holder
  • Numerical Types - org.as2lib.data.type
  • Connections - org.as2lib.io.conn
  • Unit Testing - org.as2lib.test.unit
  • Mock Object - org.as2lib.test.mock
  • Speed Testing (Profiler) - org.as2lib.test.speed
  • Application (Process and Configuration) - org.as2lib.app
  • Utilities for Arrays, Strings, Classes, … - org.as2lib.util

Download As2lib Release 0.9.2.

View the API Documentation online.

If you find bugs, if you need a new feature, if you need help or if you want to discuss functionalities or anything else with us, please use the appropriate response mechanism: Response.

We depend on the feedback from the community to improve the framework.

I hope you enjoy this new release (and remember we are not far away from release 1.0 ;).

Sunday, July 25th, 2004

AOP: AOP Framework for Flash Version 0.2

Version 0.2 is ready to hit the market. Following are the improvements that have been made:

  • The weaving process is 10 times faster.
  • The overall structure has been improved.
  • You can easily extend the framework with custom Aspects, Advices, Pointcuts and JoinPoints.
  • The weaving algorithm has been sourced out into a Weaver.
  • It is possible to directly weave into an object without affecting the underlying class.
  • Advices do not have to be classes anymore, a method and some further information is all you need (example below).

To show you the differences we are going to compare the Version 0.1 Example with the following example, that does exactly the same.
Our basis is again the class Account.

  1. import org.as2lib.core.BasicClass;
  2. import InsufficientBalanceException;
  3.  
  4. /**
  5. * @author Simon Wacker
  6. */
  7. class Account extends BasicClass {
  8.   private var balance:Number;
  9.  
  10.   public function Account(Void) {
  11.     balance = 0;
  12.   }
  13.  
  14.   public function credit(amount:Number):Number {
  15.     setBalance(balance + amount);
  16.     return balance;
  17.   }
  18.   public function debit(amount:Number):Number {
  19.     if ((balance - amount) < 0) {
  20.       throw new InsufficientBalanceException("Balance [" + balance + "] is not sufficient.", this, arguments);
  21.     }
  22.     setBalance(balance - amount);
  23.     return balance;
  24.   }
  25.   public function getBalance(Void):Number {
  26.     return balance;
  27.   }
  28.   public function setBalance(newBalance:Number):Void {
  29.     balance = newBalance;
  30.   }
  31. }

What this class does is debiting or crediting a specific amount. The debit() operation throws an InsufficientBalanceException in case the balance would be negative after debiting the amount.

  1. import org.as2lib.env.except.Exception;
  2.  
  3. /**
  4. * @author Simon Wacker
  5. */
  6. class InsufficientBalanceException extends Exception {
  7.   public function InsufficientBalanceException(message:String, thrower, args:FunctionArguments) {
  8.     super(message, thrower, args);
  9.   }
  10. }

As you can see these two classes are exactly the same as in the Version 0.1 Example.
The things changed are in the AO code. Following is the aspect.

  1. import org.as2lib.aop.Aspect;
  2. import org.as2lib.aop.aspect.AbstractAspect;
  3. import org.as2lib.aop.advice.AbstractAdvice;
  4. import org.as2lib.aop.JoinPoint;
  5. import org.as2lib.env.except.Throwable;
  6.  
  7. /**
  8. * @author Simon Wacker
  9. */
  10. class LoggingAspect extends AbstractAspect implements Aspect {
  11.   public function LoggingAspect(Void) {
  12.     addAdvice(AbstractAdvice.TYPE_AROUND, getLoggedOperationsPointcut(), aroundLoggedOperationsAdvice);
  13.   }
  14.  
  15.   private function getLoggedOperationsPointcut(Void):String {
  16.     return "execution(Account.debit()) || execution(Account.credit())";
  17.   }
  18.  
  19.   private function aroundLoggedOperationsAdvice(joinPoint:JoinPoint, args:FunctionArguments) {
  20.     trace(joinPoint.getInfo().getDeclaringType().getName() + "." + joinPoint.getInfo().getName() + "(" + args + ")");
  21.     trace("Before: " + Account(joinPoint.getThis()).getBalance());
  22.     var result;
  23.     try {
  24.       result = joinPoint.proceed(args);
  25.     } catch (exception:InsufficientBalanceException) {
  26.       trace(joinPoint.getInfo() + " throwed: " + exception.getClass().getFullName());
  27.     }
  28.     trace("After: " + Account(joinPoint.getThis()).getBalance());
  29.     trace("——————————————");
  30.     return result;
  31.   }
  32. }

When you compare this aspect with the one from Version 0.1 Example the first thing you probably recognize is the new operation aroundLoggedOperationsAdvice(). This operation contains exactly the programming logic that was in the AroundLoggedOperationsAdvice.execute() operation before. The AroundLoggedOperationsAdvice is now redundant and can be removed.
What has also changed is the way the advice is being added to the aspect. The first argument in the addAdvice() operation spcifies what type of advice it is: AbstractAspect.TYPE_AROUND. The second argument is the pointcut represented by a string and the third the method to be executed at a captured join point. It is of cource nevertheless possible to do it the old school way.
One little thing that has also changed is the method calls that have to be made to weave the whole thing. This is because the aspect is not responsible for weaving anymore but a seperate weaver.

  1. import org.as2lib.aop.Aspect;
  2. import org.as2lib.aop.Weaver;
  3. import org.as2lib.aop.weaver.SimpleWeaver;
  4.  
  5. var weaver:Weaver = new SimpleWeaver();
  6. weaver.addAspect(new LoggingAspect(), [Account]);
  7. weaver.weave();

We first create a new weaver and add an aspect to it. The first argument in the Weaver.addAspect() operation is the aspect and the second is an array containing the affected types, that means the types that shall be considered while weaving this aspect. The last call to the Weaver.weave() operation weaves all added aspects.
And that’s it. If you now execute the following example code:

  1. var account:Account = new Account();
  2. account.credit(1000);
  3. account.debit(500);
  4. account.debit(520);
  5. account.debit(480);

you will get the following output:

  1. Account.credit(1000)
  2. Before: 0
  3. After: 1000
  4. ——————————————
  5. Account.debit(500)
  6. Before: 1000
  7. After: 500
  8. ——————————————
  9. Account.debit(520)
  10. Before: 500
  11. Account.debit() throwed: InsufficientBalanceException
  12. After: 500
  13. ——————————————
  14. Account.debit(480)
  15. Before: 500
  16. After: 20
  17. ——————————————

Download the AOP Framework for Flash Version 0.2 (This is actually a CVS snapshot of the as2lib. The AOP framework is in the org.as2lib.aop package.).
Downlaod the Example.

Sunday, June 6th, 2004

AOP: How to Use the Flash AOP Framework?

To show how you can use the AOP Framework for Flash, I announced in my previous post: AOP: AOP Framework for Flash Version 0.1, I have built a little example that logs the Account.debit() and Account.credit() operations using an around advice. Following is the class Account:

  1. import org.as2lib.core.BasicClass;
  2. import InsufficientBalanceException;
  3.  
  4. /**
  5. * @author Simon Wacker
  6. */
  7. class Account extends BasicClass {
  8.   private var balance:Number;
  9.    
  10.   public function Account(Void) {
  11.     balance = 0;
  12.   }
  13.  
  14.   public function credit(amount:Number):Number {
  15.     setBalance(balance + amount);
  16.     return balance;
  17.   }
  18.   public function debit(amount:Number):Number {
  19.     if ((balance - amount) < 0) {
  20.       throw new InsufficientBalanceException("Balance [" + balance + "] is not sufficient.", this, arguments);
  21.     }
  22.     setBalance(balance - amount);
  23.     return balance;
  24.   }
  25.   public function getBalance(Void):Number {
  26.     return balance;
  27.   }
  28.   public function setBalance(newBalance:Number):Void {
  29.     balance = newBalance;
  30.   }
  31. }

As you can see this class is quite simple. I declares four operations, one to credit money from the Account, one to debit money, one to get the balance and one to set a new balance. The operation that is a little more complex than the other ones is the Account.debit() operation. It first checks if the balance is sufficient and if it is not the InsufficientBalanceException will be thrown.

  1. import org.as2lib.env.except.Exception;
  2.  
  3. /**
  4. * @author Simon Wacker
  5. */
  6. class InsufficientBalanceException extends Exception {
  7.   public function InsufficientBalanceException(message:String, thrower, args:FunctionArguments) {
  8.     super(message, thrower, args);
  9.   }
  10. }

We now have all classes to begin writing our LoggingAspect and AroundLoggedOperationsAdvice.

  1. import org.swacker.aop.Aspect;
  2. import org.swacker.aop.aspect.AbstractAspect;
  3.  
  4. /**
  5. * @author Simon Wacker
  6. */
  7. class LoggingAspect extends AbstractAspect implements Aspect {
  8.   public function LoggingAspect(Void) {
  9.     // this ensures the the class Account is loaded when the weaving process starts
  10.     Account;
  11.     // adds the affected type ‘Account’ to search for advised join points in
  12.     addAffectedTypes("Account");
  13.     // adds the advice ‘AroundLoggedOperationsAdvice’ that advices join points it captures
  14.     addAdvice(new AroundLoggedOperationsAdvice(this));
  15.   }
  16.    
  17.   public function getLoggedOperationsPointcut(Void):String {
  18.     // the pointcut in form of a string specifying the join points to be captured
  19.     return "execution(Account.debit()) || execution(Account.credit())";
  20.   }
  21. }

What we are doing here is extending the class AbstractAspect that provides us with a few basic functionalities like the weaving algorithm, the addAdvice() and the addAffectedTypes() operation. In the constructor we add the affected type ‘Account’ and the advice ‘AroundLoggedOperationsAdvice’. When the LoggingAspect.weave() operation is called, the method will look inside the added affected types for join points that are being captured by added advices.

  1. import org.as2lib.env.except.Throwable;
  2. import org.swacker.aop.advice.AroundAdvice;
  3. import org.swacker.aop.advice.AbstractAdvice;
  4. import org.swacker.aop.JoinPoint;
  5.  
  6. /**
  7. * @author Simon Wacker
  8. */
  9. class AroundLoggedOperationsAdvice extends AbstractAdvice implements AroundAdvice {
  10.   public function AroundLoggedOperationsAdvice(aspect:LoggingAspect) {
  11.     // sets the pointcut
  12.     // this operation is declared by the class AbstractAdvice
  13.     setPointcut(aspect.getLoggedOperationsPointcut());
  14.   }
  15.    
  16.   public function execute(joinPoint:JoinPoint, args:FunctionArguments) {
  17.     // the code to be executed when a captured join point is called
  18.     trace(joinPoint.getInfo().getDeclaringType().getName() + "." + joinPoint.getInfo().getName() + "(" + args + ")");
  19.     trace("Before: " + Account(joinPoint.getThis()).getBalance());
  20.     var result;
  21.     try {
  22.       result = joinPoint.proceed(args);
  23.     } catch (exception:InsufficientBalanceException) {
  24.       trace(joinPoint.getInfo() + " throwed: " + exception.getClass().getFullName());
  25.     }
  26.     trace("After: " + Account(joinPoint.getThis()).getBalance());
  27.     trace("——————————————");
  28.     return result;
  29.   }
  30. }

We are extending the AbstractAdvice that like the AbstractAspect offers needed operations like setPointcut() and an implementation of the captures() operation. We add the captured pointcut in the constructor. Then we implement the execute() operation that will be executed when any captured join point is being called. Because we are working with an around advice we have to call the proceed() operation on the join point. Otherwise the execution of the join point will be bypassed.
Now let’s write a simple test to look if it works.

  1. import org.swacker.aop.Aspect;
  2.  
  3. var aspect:Aspect = new LoggingAspect();
  4. aspect.weave();
  5.  
  6. var account:Account = new Account();
  7. account.credit(1000);
  8. account.debit(500);
  9. account.debit(520);
  10. account.debit(480);

The output should look like this:

  1. Account.credit(1000)
  2. Before: 0
  3. After: 1000
  4. ——————————————
  5. Account.debit(500)
  6. Before: 1000
  7. After: 500
  8. ——————————————
  9. Account.debit(520)
  10. Before: 500
  11. Account.debit() throwed: InsufficientBalanceException
  12. After: 500
  13. ——————————————
  14. Account.debit(480)
  15. Before: 500
  16. After: 20
  17. ——————————————

That’s it. Easy isn’t it? ;) Download the source code of the example.

Saturday, June 5th, 2004

AOP: AOP Framework for Flash Version 0.1

I have been playing around with an AOP framework for Flash for some time now and I think it is time to publish it. Right now it offers the basic AOP constructs, represented by classes, like different kinds of Advices, Pointcuts, JoinPoints and Aspects. The framework is also extensible. You could ‘easily’ add new kinds of Advices or Pointcuts. What it is lacking are lexical-structure, control-flow based pointcuts and performance (I’m not a good speed optimizer or algorithm writer). But I hope to solve all this issues in future releases. If you wanna help me, you are welcome.
Click the following link for a little UML class diagram that depicts the whole structure: AOP Framework Class Diagram.
I have also written an example to show how to use it. It is contained in the download (test/org/swacker/aop/test.fla).
Download the AOP framework and the example.
You also have to download the as2lib becuause the framework is based on it.
Download the as2lib (this version is a reviewed/newer one and not the one you can download on www.as2lib.org).

Monday, May 10th, 2004

AOP: Compile-Time Checks

A cool mechanism AspectJ offers is to declare compile-time errors and warnings. You can use this mechanism to ensure that certain rules specified in a specification don’t get broken. For example Swing’s single-thread rule. You declare errors using the following syntax:

  1. declare error : <pointcut> : <message>;

and warings using a similar one:

  1. declare warning : <pointcut> : <message>;

Errors as well as warnings will be issued when the compiler detects a join point matching a given pointcut. Errors would abort the compilation process, while warnings would just be displayed.

Example:

  1. declare error : callToHiddenCode() : "You are not allowed to call this code.";

This would produce an error if you’d call a join point captured by the pointcut callToHiddenCode().