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:
-
import org.as2lib.core.BasicClass;
-
import InsufficientBalanceException;
-
-
/**
-
* @author Simon Wacker
-
*/
-
class Account extends BasicClass {
-
private var balance:Number;
-
-
public function Account(Void) {
-
balance = 0;
-
}
-
-
public function credit(amount:Number):Number {
-
setBalance(balance + amount);
-
return balance;
-
}
-
public function debit(amount:Number):Number {
-
if ((balance - amount) < 0) {
-
throw new InsufficientBalanceException("Balance [" + balance + "] is not sufficient.", this, arguments);
-
}
-
setBalance(balance - amount);
-
return balance;
-
}
-
public function getBalance(Void):Number {
-
return balance;
-
}
-
public function setBalance(newBalance:Number):Void {
-
balance = newBalance;
-
}
-
}
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.
-
import org.as2lib.env.except.Exception;
-
-
/**
-
* @author Simon Wacker
-
*/
-
class InsufficientBalanceException extends Exception {
-
public function InsufficientBalanceException(message:String, thrower, args:FunctionArguments) {
-
super(message, thrower, args);
-
}
-
}
We now have all classes to begin writing our LoggingAspect and AroundLoggedOperationsAdvice.
-
import org.swacker.aop.Aspect;
-
import org.swacker.aop.aspect.AbstractAspect;
-
-
/**
-
* @author Simon Wacker
-
*/
-
class LoggingAspect extends AbstractAspect implements Aspect {
-
public function LoggingAspect(Void) {
-
// this ensures the the class Account is loaded when the weaving process starts
-
Account;
-
// adds the affected type ‘Account’ to search for advised join points in
-
addAffectedTypes("Account");
-
// adds the advice ‘AroundLoggedOperationsAdvice’ that advices join points it captures
-
addAdvice(new AroundLoggedOperationsAdvice(this));
-
}
-
-
public function getLoggedOperationsPointcut(Void):String {
-
// the pointcut in form of a string specifying the join points to be captured
-
return "execution(Account.debit()) || execution(Account.credit())";
-
}
-
}
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.
-
import org.as2lib.env.except.Throwable;
-
import org.swacker.aop.advice.AroundAdvice;
-
import org.swacker.aop.advice.AbstractAdvice;
-
import org.swacker.aop.JoinPoint;
-
-
/**
-
* @author Simon Wacker
-
*/
-
class AroundLoggedOperationsAdvice extends AbstractAdvice implements AroundAdvice {
-
public function AroundLoggedOperationsAdvice(aspect:LoggingAspect) {
-
// sets the pointcut
-
// this operation is declared by the class AbstractAdvice
-
setPointcut(aspect.getLoggedOperationsPointcut());
-
}
-
-
public function execute(joinPoint:JoinPoint, args:FunctionArguments) {
-
// the code to be executed when a captured join point is called
-
trace(joinPoint.getInfo().getDeclaringType().getName() + "." + joinPoint.getInfo().getName() + "(" + args + ")");
-
trace("Before: " + Account(joinPoint.getThis()).getBalance());
-
var result;
-
try {
-
result = joinPoint.proceed(args);
-
} catch (exception:InsufficientBalanceException) {
-
trace(joinPoint.getInfo() + " throwed: " + exception.getClass().getFullName());
-
}
-
trace("After: " + Account(joinPoint.getThis()).getBalance());
-
trace("——————————————");
-
return result;
-
}
-
}
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.
-
import org.swacker.aop.Aspect;
-
-
var aspect:Aspect = new LoggingAspect();
-
aspect.weave();
-
-
var account:Account = new Account();
-
account.credit(1000);
-
account.debit(500);
-
account.debit(520);
-
account.debit(480);
The output should look like this:
-
Account.credit(1000)
-
Before: 0
-
After: 1000
-
——————————————
-
Account.debit(500)
-
Before: 1000
-
After: 500
-
——————————————
-
Account.debit(520)
-
Before: 500
-
Account.debit() throwed: InsufficientBalanceException
-
After: 500
-
——————————————
-
Account.debit(480)
-
Before: 500
-
After: 20
-
——————————————
That’s it. Easy isn’t it?
Download the source code of the example.
