Introducing AS3Commons AOP

ActionScript, AOP, AS3Commons, Flex, Java 11 Comments »

The AS3Commons AOP library offers a core API with functionality to implement Aspect Oriented Programming (AOP) concepts in your application or framework. The library uses standard API terminology so that developers who are already familiar with AOP should feel immediately comfortable.

What is AOP?

For those new to AOP, here is a short explanation of the general idea. (If you are already familiar with AOP concepts, you might want to skip this part and go directly to the examples).

The basic idea behind AOP is that an application can be broken down into functional parts that can be conditionally applied to existing code. A classic example is logging, where debug information about certain methods is written to the console in order to get runtime information about the execution of the code. One approach might be to add log statements at the beginning and the end of the methods that you would like to debug. This is quite a tedious task as you need to manually add code to several places. If you ever wanted to get rid of the log statements, you would have to remove the log statements again. With AOP, you can write the logging code in a separate class and then use that class as an Advice on the class that you want to debug. You can then easily reuse the logging code on other methods of other classes.

Terminology

  • Aspect: the general concept of a cross-cutting concern. Logging, Error Handling, Method Run-Time Monitoring are useful examples.
  • Advice: an extra piece of code that needs to be applied. E.g. writing a log statement to the console.
  • Pointcut: a rule about when an Advice should be applied. For instance: all public methods of a class, all methods starting with "load", all methods that take a String parameter, ...
  • Advisor: the combination of an Advice and a Pointcut. This term is not general AOP vocabulary. It was introduced in the Spring AOP framework and is also used in AS3Commons AOP.
  • Joinpoint: a single point in the execution of the code where Advice is applied because the rule of a Pointcut has been satisfied.

Types of Advice

Advice comes in different forms, depending on what and when you want to intercept. The general types are listed below and can be applied to a Constructor, a Method or an Accessor (Getter/Setter):

  • Before: executes before the invocation
  • After: executes after the invocation
  • After Throwing: executes after the invocation threw an error
  • After Returning: executes after normal invocation (when no error was thrown)
  • Around: combines all of the above

The AS3Commons AOP library contains interfaces for all of these kinds of advice. This makes it fairly easy to implement specific advice. Interceptors can also be created that give the developer more control over the invocation than the basic advice interfaces.

How does this work?

Applying Advice to existing code is done at run-time. For this, we create a typed-proxy (also at run-time) of a class or instance that is basically a decorator (or wrapper) around the original class or object that we created. A client then works with the proxy object instead of the original object, which is completely transparent to the caller. Calls to the proxy object are then redirected to the inner (original) object during which extra logic can be executed.

Note: Creating typed-proxies at run-time is made possible by the AS3Commons-Bytecode library.

Example

Consider the following MessageWriter class, which takes an optional message as a constructor argument and has a method to write the message to the console.

Actionscript:
  1. public class MessageWriter {
  2.  
  3.   private var _message:String;
  4.  
  5.   public function MessageWriter(message:String = "") {
  6.     _message = message;
  7.   }
  8.  
  9.   public function writeMessage():void {
  10.     trace("Message: '" + _message + "'");
  11.   }
  12.  
  13. }

We can now create an advice that writes an extra message to the console whenever the writeMessage() method is called. This type of advice is "method before" advice, for which the IMethodBeforeAdvice interface can be implemented.

Actionscript:
  1. public class MethodTracerAdvice implements IMethodBeforeAdvice {
  2.  
  3.   public function MethodTracer() {
  4.   }
  5.  
  6.   public function beforeMethod(method:Method, args:Array, target:*):void {
  7.     trace("* before '" + method.name + "'");
  8.   }
  9.  
  10. }

We can now create a simple application where a proxy is created for the MessageWriter class and the MethodTracerAdvice is applied.

Actionscript:
  1. var factory:AOPProxyFactory = new AOPProxyFactory();   
  2. factory.target = MessageWriter;
  3. factory.addAdvice(new MethodTracerAdvice());
  4.  
  5. var handler:Function = function(event:OperationEvent):void {
  6.   var messageWriter:MessageWriter = factory.getProxy(["Hello World!"]);
  7.   messageWriter.writeMessage();
  8. };
  9.  
  10. var operation:IOperation = factory.load();
  11. operation.addCompleteListener(handler);

The console output would be as follows:

Actionscript:
  1. * before 'writeMessage'
  2. Message: 'Hello World!'

Notice the following things:

  • The target of the AOPProxyFactory is a class. For now, only classes can be proxied but it will also be possible to proxy existing instances.
  • The MethodTracerAdvice class implements the IMethodBeforeAdvice interface. This allows the framework to know when the advice must be executed, namely before the method invocation.
  • There is an asynchronous step in loading the proxy factory, after which the proxy can be requested. If you want to create proxies for more classes, consider using the AOPBatchProxyFactory instead. Note that even with the AOPProxyFactory, you can get multiple instances of a proxy.
  • You can pass constructor arguments to the proxy factory that will be used when creating the proxy. Although not shown in this example, it is possible to intercept and change the constructor arguments using an IConstructorBeforeAdvice.

Example with Pointcut

The previous example applies the "method before" advice on every method call. If we would add another method to the MessageWriter class, say "writeAnotherMessage", then the advice would also be invoked on that method. To control when this advice is applied, we can specify a Pointcut that will instruct the framework about when to apply the advice.

Here is the modified MessageWriter class and example.

Actionscript:
  1. public class MessageWriter {
  2.  
  3.   private var _message:String;
  4.  
  5.   public function MessageWriter(message:String = "") {
  6.     _message = message;
  7.   }
  8.  
  9.   public function writeMessage():void {
  10.     trace("Message: '" + _message + "'");
  11.   }
  12.  
  13.   public function writeAnotherMessage():void {
  14.     trace("Message: 'Konnichiwa!'");
  15.   }
  16.  
  17. }

Actionscript:
  1. var factory:AOPProxyFactory = new AOPProxyFactory();   
  2. var pointcut:IPointcut = new MethodNameMatchPointcut("writeMessage");
  3. var advice:IAdvice = new MethodTracerAdvice();
  4. factory.addAdvisor(new PointcutAdvisor(pointcut, advice));
  5. factory.target = MessageWriter;
  6.  
  7. var handler:Function = function(event:OperationEvent):void {
  8.   var messageWriter:MessageWriter = factory.getProxy(["Hello World!"]);
  9.   messageWriter.writeMessage();
  10.   messageWriter.writeAnotherMessage();
  11. };
  12.  
  13. var operation:IOperation = factory.load();
  14. operation.addCompleteListener(handler);

The console output would now be as follows:

Actionscript:
  1. * before 'writeMessage'
  2. Message: 'Hello World!'
  3. Message: 'Konnichiwa!'

Notice the following:

  • A Pointcut is defined to specify that advice should only be applied if the method name is "writeMessage"
  • The Advice and Pointcut are defined separately and then combined with a PointcutAdvisor. This allows us to reuse Pointcuts and Advice in other scenarios.

Other Types of Advice

The examples shown above only show IMethodBeforeAdvice, but there are a lot more advice interfaces that you can use. As mentioned earlier you can also intercept after invocation. This is not limited to method invocations, but you can also do this for Constructors, Getter and Setters. (Note that there are still some glitches in the alpha code concerning these types of advice.)

Conclusion

The current code is not production ready, but is certainly worth a look if you are interested in using AOP in your application or framework. We will release a first alpha release in the coming days with some samples and documentation. You can already check out the code at the AS3Commons Google Code site.

It is still early in the development so the API might change a bit before the official 1.0 release. If you have any ideas or comments about certain implementations, we're always eager to hear from you.

Some of the things on the roadmap that should make it into the release:

  • AspectJ expression language for pointcuts
  • Composite Pointcuts
  • Proxying of existing object instances

Looking forward to hearing your thoughts and enjoy coding!


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

Thoughts on Cairngorm 3 and Application Architecture

ActionScript, AS3Commons, Cairngorm, Design Patterns, Flex, Inversion of Control, Lessons learned, Microsoft, Spring ActionScript 13 Comments »

Cairngorm 3 was recently announced by Tom Sugden and Alex Uhlmann and has now been released in beta on the Adobe Opensource site.

Don't expect an updated version of the Cairngorm framework as you know it though. Cairngorm 3 is not aiming to be an MVC implementation, and thus moves away from what version 1 and 2 were, but now consists of a set of patterns and practices, together with a series of libraries that can help to solve common problems.

The Patterns & Practices Group at Microsoft have been promoting a similar mindset for quite some time actually: Prism - patterns & practices Composite Application Guidance for WPF

I can only encourage this decision as it is exactly how I personally think about application design and architecture, especially in Flex and AIR applications. This is also what we are trying to do with Spring ActionScript: our main goal is to provide a solid Inversion of Control container that supports multiple configuration options (XML, MXML, metadata driven component scanning, ...) and promote it as a foundation to build applications (and frameworks), with or without your favorite MVC framework. Although we are working on a set of base classes that provide infrastructure for your application (under the name MVCS) with Application Events, Controllers, Abstractions for service layers, ... by no means do we want to market the Spring ActionScript framework as yet another MVC implementation. (You might wonder why we are calling it MVCS then, and I'm actually wondering the same... I guess marketing and buzzwords in the opensource world are also important. All kidding aside, the name is certainly subject to change).

What's in a name

Since this is a complete change of direction for the Cairngorm framework (which it actually no longer is) I would have expected a new name. Continuing to use Cairngorm as a name is in my opinion a bad move and will cause major confusion amongst developers and other people involved in the development process. I think the best thing for Adobe, or at least their Technical Services department, would be to let go of the name and choose a new, fresh name that moves away from the past. (Besides that, who can pronounce "Cairngorm".)

Dependencies

I noticed that some of the modules that Cairngorm 3 provides depend on other libraries/frameworks, and in general the Parsley application framework. While Parsley is certainly a major player amongst the IoC/application frameworks, and I sincerely respect the author's work, I don't think this is a good decision. In case you are wondering: Yes, I would say the same thing if they decided to depend on Spring ActionScript.

The usage and choice of a concrete dependency will have consequences for the adoption and integration of the libraries that Cairngorm 3 provides. Think about it: Why would you want to pull in Parsley, perhaps only to use some of its Reflection API, if you are already running on Spring ActionScript or any other IoC container?

We, the Spring ActionScript team, have actually questioned ourselves about this in the past and have therefore decided to move all the common and reusable code from Spring ActionScript into a set of libraries known as the AS3Commons project. In that respect, I'm a bit disappointed that for instance the AS3Commons Reflect library is not used for reflection purposes, since I think it is more abstracted and unintrusive than a subset of an all-encompassing application framework. Perhaps this may be our fault of not promoting the libraries and the project enough. However, I certainly think that AS3Commons could be a wonderful project and would help to provide common libraries not only to Flex and AIR developers, but to ActionScript 3 developers in general, if it were embraced by the community.

Flex and MVC

Given that RIA technolgies are still evolving at a very fast pace, it is really remarkable to see the huge amount of MVC implementations appear. Not specifically aimed at Cairngorm (at least the previous versions), but rather at almost all MVC architectures available for Flex development, my personal feeling and experience is that the use of MVC architectures in the Adobe RIA space is almost a dogmatic thing and is not needed in most cases. The problem is that people just take an MVC framework as it is and implement it in their applications. More than often not questioning whether or not its usage is justified. Things that could easily and cleverly be solved are ripped apart across layers of the architecture, introducing levels of indirection that are in most cases not needed. The only thing they add is complexity and counter-intuitive development practices.

One of the main arguments for using an MVC framework is that the code is "easy to understand". Of course the code will be easy to understand if you have been developing with the framework of choice for the N-th time or if you have been digging into the code for a serious amount of time, but ask a newcomer to look at the code and try to explain to you what it is actually doing... I think you'll be surprised by the responses.

I'm not saying that the use of a particular MVC framework is de facto a bad thing, but the "religious" use and the blind adoption and implementation make a framework a killer for your application. I would encourage everyone to start their next project without an MVC framework and just use the Flex framework with a healthy knowledge of design and presentation patterns. And even if you are using an MVC implementation, think about each layer you introduce, why you need it and the pros and cons it brings.

Conclusion

It's good to see that Adobe is rethinking their approach to RIA architecture and development practices. I also hope that they will be more open to community input and feedback than they were in the past. Although they did several attempts at engaging the community, I don't think they really succeeded in that. If not open enough, people will just continue to fork the "framework" and provide extensions that will end up in alternative implementations anyway.

I'm looking forward to seeing how all of this evolves.


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

Introducing the AS3Commons project

ActionScript, Air, AS3Commons, Flash, Flex 5 Comments »

While working on the Spring ActionScript framework, we wrote a lot of code that could perfectly be used outside of the framework. That's why we decided to start the AS3Commons project, based on idea of the Apache Commons project, and provide a set of core libraries useful to every ActionScript 3.0 developer.

This announcement is also the immediate release of 2 of the libraries included:

  • AS3Commons-Reflect: a reflection library
  • AS3Commons-Logging: an abstraction layer over logging frameworks

Note: we realize there is another as3commons library out there. However this library is no longer being maintained and developed as confirmed by the author. We apologize in advance for the confusion this might cause. We are currently looking into the code and will try to include/replace the functionality in the new project.

AS3Commons-Reflect

This is a reflection library, or a clear API written around describeType(). It allows you to get runtime information about classes and objects running in your application, like the properties and methods available in a class, the metadata associated with a certain property, ... and it also allows you to dynamically instantiate objects and invoke their methods.

We had previously moved this from the Spring ActionScript sources to the AS3Reflect project. However, since we had plans of extracting other part of the framework as well, we decided to bundle everything under the AS3Commons project. The AS3Reflect library is hence no longer available and we advice all users to update to the new release.

For more info, please see http://www.as3commons.org/as3-commons-reflect

AS3Commons-Logging

This is a logging abstraction layer over existing logging frameworks. It is a lightweight library that offers a logger interface and a set of adapters and decorators for existing logging frameworks, like the logging API in the Flex framework.

It is perfectly fit for library and framework developers that want to enable logging information in their distributed libraries without tying their code to a specific logging framework. Logging happens via the logger interfaces provided by AS3Commons-Logging and users are then able to configure the logger with the implementation they prefer.

Here's a small example:

Actionscript:
  1. // configure the LoggerFactory with the Flex logging framework
  2. private static var loggerSetup:* = (LoggerFactory.loggerFactory = new FlexLoggerFactory());
  3.  
  4. // get a logger from the factory, in which all log statements will be handled by the Flex logger
  5. private static var logger:ILogger = LoggerFactory.getLogger("com.domain.MyClass");

We will update the project with new adapters for existing logging frameworks. Let us know if you have any framework that you would like to see supported.

For more info, please see: http://www.as3commons.org/as3-commons-logging

Get Involved

We welcome participation from all that are interested, at all skill levels. Coding, documentation and testing are all critical parts of the software development process. If you are interested in participating in any of these aspects, please join us! You can leave a comment or mail me at christophe.herreman [at] gmail [dot] com.

www.as3commons.org


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 
WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in