SlideShare a Scribd company logo
1 of 52
Download to read offline
How to build
        an AOP framework
(and how to lose your sanity in the process)

Roland Zwaga                    Christophe Herreman
@mechhead                       @herrodius
Agenda
- Quick AOP primer
- Typed Proxies
- ABC
- AS3Commons Bytecode
- AS3Commons AOP
About us
Two geeks from Holland and Belgium

Run Stack & Heap, a development and consulting company
based in Belgium

Core members of Spring ActionScript and AS3Commons
Aspect Oriented Programming
AOP Primer: example "Security"
class MyService {

    public function getData():MyData {
       // get data
    }

    public function getSecretData():MyData {
       // get secret data
    }

    public function getMoreSecretData():MyData {
       // get more secret data
    }

}
AOP Primer: example "Security"

Requirement

The methods getSecretData and
getMoreSecretData may only be invoked by authorized
users.
AOP Primer: example "Security"
...
      public function getData():MyData {
         // get data
      }

      public function getSecretData():MyData {
         if (userIsAuthorized) {
             // get secret data
         } else {
             throw new Error("User is not authorized");
         }
      }
...
AOP Primer: example "Security"
...
      public function getMoreSecretData():MyData {
         if (userIsAuthorized) {
             // get more secret data
         } else {
             throw new Error("User is not authorized");
         }
      }
...
AOP Primer: example "Security"
Notice the following:

- code is "cluttered" with extra security code; lost focus
- code duplication
- the above will increase with more methods and services

What if:

- security requirements change?
- service class must be used in other (non-secure) context
AOP Primer: example "Security"
The AOP solution:

Separate the security code from the service code and
merge them.
AOP Primer: example "Security"
public class AuthorizationAdvice implements
       IMethodBeforeAdvice {

    public function beforeMethod( method:Method,
                                  args:Array,
                                  target:* ):void {
       if (method.name == "getSecretData"
              || method.name == "getMoreSecretData") {
           if (!userIsAuthorized) {
              throw new Error("User is not authorized");
           }
       }
    }
}
AOP Primer: example "Security"
var factory:AOPProxyFactory = new AOPProxyFactory();
factory.target = MyService;
factory.addAdvice(new AuthorizationAdvice());

var operation:IOperation = factory.load();
operation.addCompleteListener(factory_completeHandler);

function factory_completeHandler(event:OperationEvent):
void {
   var service:MyService = factory.getProxy();
   service.getData();
   service.getSecretData();
}
AOP Primer: Terminology

Aspect      The general concept of a cross-cutting
Advice      concern.
Pointcut
Joinpoint   In the example: "security"
Advisor
            Logging, Error Handling, Method Run-Time
            Monitoring, Validation, etc. are other useful
            examples.
AOP Primer: Terminology

Aspect      An extra piece of code that needs to be
Advice      applied.
Pointcut
Joinpoint   In the example: throw an error if the user
Advisor     is not authorized

            Types of advice:
            - before
            - after
            - afterThrows
            - around
AOP Primer: Terminology

Aspect      A rule about when an Advice should be
Advice      applied.
Pointcut
Joinpoint   In the example: the methods
Advisor     "getSecretData" and "getMoreSecretData"

            Other examples: all public methods of a
            class, all methods starting with "load", all
            methods that take a String parameter, ...
AOP Primer: Terminology

Aspect      A single point in the execution of the code
Advice      where Advice is applied because the rule of a
Pointcut    Pointcut has been satisfied.
Joinpoint
Advisor
AOP Primer: Terminology

Aspect      The combination of an Advice and a
Advice      Pointcut. This term is not general AOP
Pointcut    vocabulary. It was introduced in the (Java)
Joinpoint   Spring AOP framework and is also used in
Advisor     AS3Commons AOP.
Dynamic Typed Proxies
Runtime generated dynamic proxies

● A subclass of a class or an implementation of an
  interface to which we'd like to add extra functionality
  (aspects in AOP)

● Has a reference to an
  IMethodInvocationInterceptor injected

● The (sub)class does not exist as ActionScript code.
  Instead, it gets generated at runtime

● Not the same as flash.utils.Proxy
We asked Adobe for Typed Proxies




                     ... but it didn't happen.
The original method

public function conferenceEvaluator(name:String):String
{
   if (name == '360|Flex') {
       return 'awesome';
   }
   return 'meh';
}
The proxied method

override public function conferenceEvaluator(name:String):
String {
   return methodInvocationInterceptor.intercept
   (
       this,
       InvocationKind.METHOD,
       new QName("", "conferenceEvaluator"),
       [name],
       super.conferenceEvaluator
   );
}
How the bloody hell do we do this?
●   AS3eval? (eval.hurlant.com)
●   flash.utils.Proxy class?
●   Flemit and Floxy? (asmock.sourceforge.org)
●   Loom-as3!!

Loom-as3 gets discontinued prematurely :(

Oops... Time to get our hands dirty... (and lose our sanity)
The birth of AS3Commons Bytecode!
ABC
ActionScript Byte Code
AS3Commons Bytecode
AS3Commons-Bytecode API
General purpose ABC Bytecode API, not just aimed at
AOP.

●   ABCDeserializer
●   ABCSerializer
●   ByteCodeType (reflection)
●   AbcBuilder (emit API)
●   ProxyFactory (proxy API)
Let's generate this class
package org {

    public class Conferences()
    {
       super();
    }

    public function myFavoriteConference():String
    {
       return "360|Flex!";
    }

}
Creating the AbcFile manually, loads of fun!
var abcFile:AbcFile = new AbcFile();                                                           var method:MethodInfo = new MethodInfo();
var instanceInfo:InstanceInfo = new InstanceInfo();                                            method.methodName = "org.Conferences/:myFavoriteConference";
instanceInfo.classMultiname = new QualifiedName("Conferences", new LNamespace(NamespaceKind.   method.returnType = new QualifiedName("String", LNamespace.PUBLIC);
PACKAGE_NAMESPACE, "org"));
                                                                                               method.methodBody.localCount = 1;
var constructor:MethodInfo = new MethodInfo();
                                                                                               method.methodBody.initScopeDepth = 1;
constructor.methodName = "org.Conferences/:Conferences";
                                                                                               method.methodBody.maxScopeDepth = 2;
constructor.returnType = new QualifiedName("*", LNamespace.ASTERISK);
                                                                                               method.methodBody.maxStack = 2;
constructor.methodBody = new MethodBody();
                                                                                               method.methodBody.opcodes.push(Opcode.getlocal_0.op());
constructor.methodBody.localCount = 1;
                                                                                               method.methodBody.opcodes.push(Opcode.pushscope.op());
constructor.methodBody.initScopeDepth = 1;
                                                                                               method.methodBody.opcodes.push(Opcode.pushstring.op(["360|Flex!"]));
constructor.methodBody.maxScopeDepth = 2;
                                                                                               method.methodBody.opcodes.push(Opcode.returnvalue.op());
constructor.methodBody.maxStack = 1;
                                                                                               trait = new MethodTrait();
constructor.methodBody.opcodes.push(Opcode.getlocal_0.op());
                                                                                               trait.traitKind = TraitKind.METHOD;
constructor.methodBody.opcodes.push(Opcode.pushscope.op());
                                                                                               method.as3commonsByteCodeAssignedMethodTrait = trait;
constructor.methodBody.opcodes.push(Opcode.getlocal_0.op());
                                                                                               instanceInfo.methodInfo.push(method);
constructor.methodBody.opcodes.push(Opcode.constructsuper.op([0]));
                                                                                               var scriptInfo:ScriptInfo = new ScriptInfo();
constructor.methodBody.opcodes.push(Opcode.returnvoid.op());
                                                                                               var scriptInitializer:MethodInfo = new MethodInfo();
var trait:MethodTrait = new MethodTrait();
                                                                                               scriptInfo.scriptInitializer = scriptInitializer;
trait.traitKind = TraitKind.METHOD;
                                                                                               scriptInitializer.methodName = "";
constructor.as3commonsByteCodeAssignedMethodTrait = trait;
                                                                                               scriptInitializer.returnType = new QualifiedName("*", LNamespace.ASTERISK);
instanceInfo.addTrait(trait);
                                                                                               scriptInitializer.methodBody.opcodes.push(Opcode.getlocal_0.op());
instanceInfo.constructor = constructor;
                                                                                               scriptInitializer.methodBody.opcodes.push(Opcode.pushscope.op());
var staticConstructor:MethodInfo = new MethodInfo();
                                                                                               scriptInitializer.methodBody.opcodes.push(Opcode.getscopeobject.op([0]));
staticConstructor.methodName = "org.Conferences:Conferences:::Conferences$cinit";
                                                                                               var mn:QualifiedName = new QualifiedName("Conferences", new LNamespace(NamespaceKind.PACKAGE_NAMESPACE,
staticConstructor.returnType = new QualifiedName("*", LNamespace.ASTERISK);                    "org"));
staticConstructor.methodBody = new MethodBody();                                               scriptInitializer.methodBody.opcodes.push(Opcode.findpropstrict.op([mn])) //
staticConstructor.methodBody.localCount = 1;                                                   scriptInitializer.methodBody.opcodes.push(Opcode.getproperty.op([mn]));
staticConstructor.methodBody.initScopeDepth = 1;                                               scriptInitializer.methodBody.opcodes.push(Opcode.pushscope.op());
staticConstructor.methodBody.maxScopeDepth = 2;                                                scriptInitializer.methodBody.opcodes.push(Opcode.popscope.op());
staticConstructor.methodBody.maxStack = 1;                                                     scriptInitializer.methodBody.opcodes.push(Opcode.newclass, [classInfo]);
staticConstructor.methodBody.opcodes.push(Opcode.getlocal_0.op());                             scriptInitializer.methodBody.opcodes.push(Opcode.initproperty, [mn]);
staticConstructor.methodBody.opcodes.push(Opcode.pushscope.op());                              scriptInitializer.methodBody.opcodes.push(Opcode.returnvoid);
staticConstructor.methodBody.opcodes.push(Opcode.returnvoid.op());                             abcFile.addClassInfo(classInfo);
var classInfo:ClassInfo = new ClassInfo();                                                     abcFile.addScriptInfo(scriptInfo);
classInfo.staticInitializer = staticConstructor;                                               abcFile.addInstanceInfo(instanceInfo);
Generate a class with the emit API
var abcBuilder:IAbcBuilder = new AbcBuilder();
var classbuilder:IClassBuilder =
   abcBuilder.defineClass("org.Conferences");

var methodBuilder:IMethodBuilder = classbuilder.
defineMethod("myFavoriteConference");

methodBuilder.returnType = "String";
methodBuilder.addOpcode(Opcode.getlocal_0)
              .addOpcode(Opcode.pushscope)
              .addOpcode(Opcode.pushstring,["360|Flex!"])
              .addOpcode(Opcode.returnvalue);
Loading the class into the AVM
abcBuilder.addEventListener(Event.COMPLETE,
loadedHandler);

abcBuilder.buildAndLoad();

function loadedHandler(event:Event):void {
  var clazz:Class =
          ApplicationDomain.currentDomain.getDefinition
       ("org.Conferences") as Class;
  var instance:* = new clazz();
  var result:String = instance.myFavoriteConference();
  // result == '360|Flex!'
}
The feeling after this finally works...
ProxyFactory: Generating proxy
var factory:IProxyFactory = new ProxyFactory();
factory.defineProxy(Conferences);
factory.generateProxyClasses();
factory.addEventListener(
   ProxyFactoryEvent.GET_METHOD_INVOCATION_INTERCEPTOR,
   onProxyCreate);
factory.addEventListener(Event.COMPLETE, onComplete);
factory.buildAndLoad();

function onComplete(event:Event):void {
   var conf:Conference = factory.createProxy(Conference);
   // This will return the proxy class instance!
}
ProxyFactory: Injecting interceptors
function onProxyCreate(event:ProxyFactoryEvent):void {
   var interceptor:IMethodInvocationInterceptor =
       createInterceptor();
   event.methodInvocationInterceptor = interceptor;
}

function createInterceptor():IMethodInvocationInterceptor
{
   var result:IMethodInvocationInterceptor = new
       BasicMethodInvocationInterceptor();
   //register IInterceptors...
}
IInterceptor interface
public interface IInterceptor {

    function intercept(invocation:IMethodInvocation):void;

}
IMethodInvocation interface
public interface IMethodInvocation {

    function   get   kind():InvocationKind;
    function   get   targetInstance():Object;
    function   get   targetMember():QName;
    function   get   targetMethod():Function;
    function   get   arguments():Array;
    function   get   proceed():Boolean;
    function   set   proceed(value:Boolean):void;
    function   get   returnValue():*;
    function   set   returnValue(value:*):void;

}
So, how to build an AOP framework?

●   ABC - I hate myself and I want to die
●   AbcBuilder - I think the emit API sucks
●   Emit API - I think the proxy API sucks
●   Proxy API - I love AS3Commons-Bytecode!

Pick your poison!
AS3Commons AOP
AS3Commons AOP
Advice interfaces (some of them)

- IMethodBeforeAdvice
   beforeMethod(method:Method, args:Array, target:*):void;

- IConstructorAfterAdvice
   afterConstructor(constructor:Constructor, args:Array,
                    target:*):void;

- ISetterAroundAdvice
   beforeSetter(setter:Accessor, target:*, value:*):void;
   afterSetter(setter:Accessor):void;
   afterSetterThrows(setter:Accessor, value:*, target:*,
                       error:Error):void;
AS3Commons AOP
Advisor

Combines Pointcut (when) and Advice (what).

Actually, Advice is always wrapped in an Advisor:

// in AOPProxyFactory...
public function addAdvice(advice:IAdvice, target:*=null):void {
   addAdvisor(new AlwaysMatchingPointcutAdvisor(advice),
       target);
}
AS3Commons AOP
Adding an advisor to the proxy factory (1/2)

var factory:AOPProxyFactory = new AOPProxyFactory();

var pointcut:IPointcut = new
   MethodNameMatchPointcut(["getSecretData","
getMoreSecretData"]);

var advice:IAdvice = new AuthenticationAdvice();

factory.addAdvisor(new PointcutAdvisor(pointcut, advice));
AS3Commons AOP
Adding an advisor to the proxy factory (2/2)

The AuthenticationAdvice can now be simplified:

public function beforeMethod( method:Method,
                               args:Array,
                               target:*):void {
       if (method.name == "getSecretData"
              || method.name == "getMoreSecretData") {
          if (!userIsAuthorized) {
              throw new Error("User is not authorized");
          }
       }
   }
}
AS3Commons AOP
Pointcuts

- Name matching
- Regular expression matching
- Binary: combine pointcuts (and, or, ...)
AS3Commons AOP
Interceptors

Use an interceptor if you want full control over the execution of
the advice code.
public class StringToUppercaseSetterInterceptor implements
       ISetterInterceptor {

    function interceptSetter(invocation:ISetterInvocation) {
       if (invocation.value is String) {
           invocation.value = invocation.value.toUpperCase();
       }
       invocation.proceed();
    }
}
AS3Commons AOP
AOPProxyFactory

Configure it with advice, advisors and/or interceptors and
get proxies from it.

var factory:AOPProxyFactory = new AOPProxyFactory();
factory.target = MyService;
factory.addAdvice(new AuthorizationAdvice());
... (asynchronous loading of the factory)
var service:MyService = factory.getProxy();


Hides Bytecode's ProxyFactory interceptor details.
AS3Commons AOP
AOPBatchProxyFactory

Proxy factory to create multiple proxies. Used inside the
AOPProxyFactory.

Uses AS3Commons-Bytecode to generate the proxies.

The interceptor we create is an AdvisorInterceptor.
AS3Commons AOP
AdvisorInterceptor

see Chain of Responsibility design pattern




When using an interceptor, call the proceed() method on the
interceptor if you want to move down the chain. If not, the chain
will be ended.

The framework does this for you when using Advice/Advisors.
Easier, but less control.
AS3Commons AOP
What's to come and what is possible?

- Pointcut dialect & metadata/annotation driven pointcut
configuration

- Integration with Spring ActionScript or other Dependency
Injection frameworks
More info

www.as3commons.org

ActionScript Virtual Machine 2 Spec: http://www.adobe.
com/content/dam/Adobe/en/devnet/actionscript/articles/avm2
overview.pdf

Twitter

@mechhead, @herrodius, @as3commons, @stackandheap
Questions ?
Thank you !

More Related Content

What's hot

Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...julien.ponge
 
Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113SOAT
 
Notes for xx_use_serialgc
Notes for xx_use_serialgcNotes for xx_use_serialgc
Notes for xx_use_serialgcytoshima
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6Fiyaz Hasan
 
10. session 10 loops and arrays
10. session 10   loops and arrays10. session 10   loops and arrays
10. session 10 loops and arraysPhúc Đỗ
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydneyjulien.ponge
 
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019corehard_by
 
Synthesizing API Usage Examples
Synthesizing API Usage Examples Synthesizing API Usage Examples
Synthesizing API Usage Examples Ray Buse
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)Alok Kumar
 
The Ring programming language version 1.10 book - Part 17 of 212
The Ring programming language version 1.10 book - Part 17 of 212The Ring programming language version 1.10 book - Part 17 of 212
The Ring programming language version 1.10 book - Part 17 of 212Mahmoud Samir Fayed
 
Exception Handling
Exception HandlingException Handling
Exception HandlingSunil OS
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)David Rodenas
 

What's hot (20)

Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
Java 7 Launch Event at LyonJUG, Lyon France. Fork / Join framework and Projec...
 
Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113
 
Live Updating Swift Code
Live Updating Swift CodeLive Updating Swift Code
Live Updating Swift Code
 
Notes for xx_use_serialgc
Notes for xx_use_serialgcNotes for xx_use_serialgc
Notes for xx_use_serialgc
 
E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
What’s new in C# 6
What’s new in C# 6What’s new in C# 6
What’s new in C# 6
 
10. session 10 loops and arrays
10. session 10   loops and arrays10. session 10   loops and arrays
10. session 10 loops and arrays
 
Software Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW SydneySoftware Testing - Invited Lecture at UNSW Sydney
Software Testing - Invited Lecture at UNSW Sydney
 
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019Статичный SQL в С++14. Евгений Захаров ➠  CoreHard Autumn 2019
Статичный SQL в С++14. Евгений Захаров ➠ CoreHard Autumn 2019
 
Synthesizing API Usage Examples
Synthesizing API Usage Examples Synthesizing API Usage Examples
Synthesizing API Usage Examples
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)
 
The Ring programming language version 1.10 book - Part 17 of 212
The Ring programming language version 1.10 book - Part 17 of 212The Ring programming language version 1.10 book - Part 17 of 212
The Ring programming language version 1.10 book - Part 17 of 212
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
What's new in Liferay Mobile SDK 2.0 for Android
What's new in Liferay Mobile SDK 2.0 for AndroidWhat's new in Liferay Mobile SDK 2.0 for Android
What's new in Liferay Mobile SDK 2.0 for Android
 
Exception Handling
Exception HandlingException Handling
Exception Handling
 
Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
 
droidparts
droidpartsdroidparts
droidparts
 
ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)ES3-2020-06 Test Driven Development (TDD)
ES3-2020-06 Test Driven Development (TDD)
 

Viewers also liked

Giáo trình học Html5/Css3
Giáo trình học Html5/Css3Giáo trình học Html5/Css3
Giáo trình học Html5/Css3Ho Ngoc Tan
 
Essential action script 3.0
Essential action script 3.0Essential action script 3.0
Essential action script 3.0UltimateCodeX
 
Giáo trình Flash CS5 và Action Script 3.0
Giáo trình Flash CS5 và Action Script 3.0Giáo trình Flash CS5 và Action Script 3.0
Giáo trình Flash CS5 và Action Script 3.0Kenny Nguyen
 
Action script for designers
Action script for designersAction script for designers
Action script for designersoyunbaga
 
Creative Programming in ActionScript 3.0
Creative Programming in ActionScript 3.0Creative Programming in ActionScript 3.0
Creative Programming in ActionScript 3.0Peter Elst
 
ActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsSaurabh Narula
 
Giáo trình đọc hiểu bản vẽ cơ khí
Giáo trình đọc hiểu bản vẽ cơ khíGiáo trình đọc hiểu bản vẽ cơ khí
Giáo trình đọc hiểu bản vẽ cơ khíTrung tâm Advance Cad
 
Giáo trình học tiếng anh Student book 1
Giáo trình học tiếng anh Student book 1Giáo trình học tiếng anh Student book 1
Giáo trình học tiếng anh Student book 1Keziah Huong
 
Giáo trình giảng dạy Autocad 2016 cơ bản
Giáo trình giảng dạy Autocad 2016 cơ bảnGiáo trình giảng dạy Autocad 2016 cơ bản
Giáo trình giảng dạy Autocad 2016 cơ bảnTrung tâm Advance Cad
 
Giáo trình Robot Structural 2016 Tập 2
Giáo trình Robot Structural 2016 Tập 2Giáo trình Robot Structural 2016 Tập 2
Giáo trình Robot Structural 2016 Tập 2Huytraining
 

Viewers also liked (10)

Giáo trình học Html5/Css3
Giáo trình học Html5/Css3Giáo trình học Html5/Css3
Giáo trình học Html5/Css3
 
Essential action script 3.0
Essential action script 3.0Essential action script 3.0
Essential action script 3.0
 
Giáo trình Flash CS5 và Action Script 3.0
Giáo trình Flash CS5 và Action Script 3.0Giáo trình Flash CS5 và Action Script 3.0
Giáo trình Flash CS5 và Action Script 3.0
 
Action script for designers
Action script for designersAction script for designers
Action script for designers
 
Creative Programming in ActionScript 3.0
Creative Programming in ActionScript 3.0Creative Programming in ActionScript 3.0
Creative Programming in ActionScript 3.0
 
ActionScript 3.0 Fundamentals
ActionScript 3.0 FundamentalsActionScript 3.0 Fundamentals
ActionScript 3.0 Fundamentals
 
Giáo trình đọc hiểu bản vẽ cơ khí
Giáo trình đọc hiểu bản vẽ cơ khíGiáo trình đọc hiểu bản vẽ cơ khí
Giáo trình đọc hiểu bản vẽ cơ khí
 
Giáo trình học tiếng anh Student book 1
Giáo trình học tiếng anh Student book 1Giáo trình học tiếng anh Student book 1
Giáo trình học tiếng anh Student book 1
 
Giáo trình giảng dạy Autocad 2016 cơ bản
Giáo trình giảng dạy Autocad 2016 cơ bảnGiáo trình giảng dạy Autocad 2016 cơ bản
Giáo trình giảng dạy Autocad 2016 cơ bản
 
Giáo trình Robot Structural 2016 Tập 2
Giáo trình Robot Structural 2016 Tập 2Giáo trình Robot Structural 2016 Tập 2
Giáo trình Robot Structural 2016 Tập 2
 

Similar to How to build an AOP framework in ActionScript

How to Write Node.js Module
How to Write Node.js ModuleHow to Write Node.js Module
How to Write Node.js ModuleFred Chien
 
Analysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMSAnalysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMSPVS-Studio
 
TWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonTWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonCodemotion
 
Salesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUGSalesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUGvraopolisetti
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?Andrey Karpov
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksMongoDB
 
Compatibility Detector Tool of Chrome extensions
Compatibility Detector Tool of Chrome extensionsCompatibility Detector Tool of Chrome extensions
Compatibility Detector Tool of Chrome extensionsKai Cui
 
Automated malware analysis
Automated malware analysisAutomated malware analysis
Automated malware analysisIbrahim Baliç
 
jSession #4 - Maciej Puchalski - Zaawansowany retrofit
jSession #4 - Maciej Puchalski - Zaawansowany retrofitjSession #4 - Maciej Puchalski - Zaawansowany retrofit
jSession #4 - Maciej Puchalski - Zaawansowany retrofitjSession
 
Javascript Frameworks for Joomla
Javascript Frameworks for JoomlaJavascript Frameworks for Joomla
Javascript Frameworks for JoomlaLuke Summerfield
 
Static Analysis in IDEA
Static Analysis in IDEAStatic Analysis in IDEA
Static Analysis in IDEAHamletDRC
 

Similar to How to build an AOP framework in ActionScript (20)

OpenCMIS Part 1
OpenCMIS Part 1OpenCMIS Part 1
OpenCMIS Part 1
 
How to Write Node.js Module
How to Write Node.js ModuleHow to Write Node.js Module
How to Write Node.js Module
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 
Analysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMSAnalysis of bugs in Orchard CMS
Analysis of bugs in Orchard CMS
 
Twins: OOP and FP
Twins: OOP and FPTwins: OOP and FP
Twins: OOP and FP
 
TWINS: OOP and FP - Warburton
TWINS: OOP and FP - WarburtonTWINS: OOP and FP - Warburton
TWINS: OOP and FP - Warburton
 
Salesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUGSalesforce Batch processing - Atlanta SFUG
Salesforce Batch processing - Atlanta SFUG
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
Compatibility Detector Tool of Chrome extensions
Compatibility Detector Tool of Chrome extensionsCompatibility Detector Tool of Chrome extensions
Compatibility Detector Tool of Chrome extensions
 
Automated malware analysis
Automated malware analysisAutomated malware analysis
Automated malware analysis
 
jSession #4 - Maciej Puchalski - Zaawansowany retrofit
jSession #4 - Maciej Puchalski - Zaawansowany retrofitjSession #4 - Maciej Puchalski - Zaawansowany retrofit
jSession #4 - Maciej Puchalski - Zaawansowany retrofit
 
Javascript Frameworks for Joomla
Javascript Frameworks for JoomlaJavascript Frameworks for Joomla
Javascript Frameworks for Joomla
 
Android - Api & Debugging in Android
Android - Api & Debugging in AndroidAndroid - Api & Debugging in Android
Android - Api & Debugging in Android
 
meet.js - QooXDoo
meet.js - QooXDoomeet.js - QooXDoo
meet.js - QooXDoo
 
Java practical
Java practicalJava practical
Java practical
 
Static Analysis in IDEA
Static Analysis in IDEAStatic Analysis in IDEA
Static Analysis in IDEA
 
Test api
Test apiTest api
Test api
 

More from Christophe Herreman

More from Christophe Herreman (7)

De kathedraal en de bazaar
De kathedraal en de bazaarDe kathedraal en de bazaar
De kathedraal en de bazaar
 
Stuff you didn't know about action script
Stuff you didn't know about action scriptStuff you didn't know about action script
Stuff you didn't know about action script
 
GradleFX
GradleFXGradleFX
GradleFX
 
AS3Commons Introduction
AS3Commons IntroductionAS3Commons Introduction
AS3Commons Introduction
 
Spring Actionscript at Devoxx
Spring Actionscript at DevoxxSpring Actionscript at Devoxx
Spring Actionscript at Devoxx
 
Spring ActionScript
Spring ActionScriptSpring ActionScript
Spring ActionScript
 
The Prana IoC Container
The Prana IoC ContainerThe Prana IoC Container
The Prana IoC Container
 

Recently uploaded

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdfChristopherTHyatt
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 

Recently uploaded (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 

How to build an AOP framework in ActionScript

  • 1. How to build an AOP framework (and how to lose your sanity in the process) Roland Zwaga Christophe Herreman @mechhead @herrodius
  • 2. Agenda - Quick AOP primer - Typed Proxies - ABC - AS3Commons Bytecode - AS3Commons AOP
  • 3. About us Two geeks from Holland and Belgium Run Stack & Heap, a development and consulting company based in Belgium Core members of Spring ActionScript and AS3Commons
  • 5. AOP Primer: example "Security" class MyService { public function getData():MyData { // get data } public function getSecretData():MyData { // get secret data } public function getMoreSecretData():MyData { // get more secret data } }
  • 6. AOP Primer: example "Security" Requirement The methods getSecretData and getMoreSecretData may only be invoked by authorized users.
  • 7. AOP Primer: example "Security" ... public function getData():MyData { // get data } public function getSecretData():MyData { if (userIsAuthorized) { // get secret data } else { throw new Error("User is not authorized"); } } ...
  • 8. AOP Primer: example "Security" ... public function getMoreSecretData():MyData { if (userIsAuthorized) { // get more secret data } else { throw new Error("User is not authorized"); } } ...
  • 9. AOP Primer: example "Security" Notice the following: - code is "cluttered" with extra security code; lost focus - code duplication - the above will increase with more methods and services What if: - security requirements change? - service class must be used in other (non-secure) context
  • 10. AOP Primer: example "Security" The AOP solution: Separate the security code from the service code and merge them.
  • 11. AOP Primer: example "Security" public class AuthorizationAdvice implements IMethodBeforeAdvice { public function beforeMethod( method:Method, args:Array, target:* ):void { if (method.name == "getSecretData" || method.name == "getMoreSecretData") { if (!userIsAuthorized) { throw new Error("User is not authorized"); } } } }
  • 12. AOP Primer: example "Security" var factory:AOPProxyFactory = new AOPProxyFactory(); factory.target = MyService; factory.addAdvice(new AuthorizationAdvice()); var operation:IOperation = factory.load(); operation.addCompleteListener(factory_completeHandler); function factory_completeHandler(event:OperationEvent): void { var service:MyService = factory.getProxy(); service.getData(); service.getSecretData(); }
  • 13. AOP Primer: Terminology Aspect The general concept of a cross-cutting Advice concern. Pointcut Joinpoint In the example: "security" Advisor Logging, Error Handling, Method Run-Time Monitoring, Validation, etc. are other useful examples.
  • 14. AOP Primer: Terminology Aspect An extra piece of code that needs to be Advice applied. Pointcut Joinpoint In the example: throw an error if the user Advisor is not authorized Types of advice: - before - after - afterThrows - around
  • 15. AOP Primer: Terminology Aspect A rule about when an Advice should be Advice applied. Pointcut Joinpoint In the example: the methods Advisor "getSecretData" and "getMoreSecretData" Other examples: all public methods of a class, all methods starting with "load", all methods that take a String parameter, ...
  • 16. AOP Primer: Terminology Aspect A single point in the execution of the code Advice where Advice is applied because the rule of a Pointcut Pointcut has been satisfied. Joinpoint Advisor
  • 17. AOP Primer: Terminology Aspect The combination of an Advice and a Advice Pointcut. This term is not general AOP Pointcut vocabulary. It was introduced in the (Java) Joinpoint Spring AOP framework and is also used in Advisor AS3Commons AOP.
  • 19. Runtime generated dynamic proxies ● A subclass of a class or an implementation of an interface to which we'd like to add extra functionality (aspects in AOP) ● Has a reference to an IMethodInvocationInterceptor injected ● The (sub)class does not exist as ActionScript code. Instead, it gets generated at runtime ● Not the same as flash.utils.Proxy
  • 20. We asked Adobe for Typed Proxies ... but it didn't happen.
  • 21. The original method public function conferenceEvaluator(name:String):String { if (name == '360|Flex') { return 'awesome'; } return 'meh'; }
  • 22. The proxied method override public function conferenceEvaluator(name:String): String { return methodInvocationInterceptor.intercept ( this, InvocationKind.METHOD, new QName("", "conferenceEvaluator"), [name], super.conferenceEvaluator ); }
  • 23. How the bloody hell do we do this? ● AS3eval? (eval.hurlant.com) ● flash.utils.Proxy class? ● Flemit and Floxy? (asmock.sourceforge.org) ● Loom-as3!! Loom-as3 gets discontinued prematurely :( Oops... Time to get our hands dirty... (and lose our sanity) The birth of AS3Commons Bytecode!
  • 25.
  • 26.
  • 28. AS3Commons-Bytecode API General purpose ABC Bytecode API, not just aimed at AOP. ● ABCDeserializer ● ABCSerializer ● ByteCodeType (reflection) ● AbcBuilder (emit API) ● ProxyFactory (proxy API)
  • 29. Let's generate this class package org { public class Conferences() { super(); } public function myFavoriteConference():String { return "360|Flex!"; } }
  • 30. Creating the AbcFile manually, loads of fun! var abcFile:AbcFile = new AbcFile(); var method:MethodInfo = new MethodInfo(); var instanceInfo:InstanceInfo = new InstanceInfo(); method.methodName = "org.Conferences/:myFavoriteConference"; instanceInfo.classMultiname = new QualifiedName("Conferences", new LNamespace(NamespaceKind. method.returnType = new QualifiedName("String", LNamespace.PUBLIC); PACKAGE_NAMESPACE, "org")); method.methodBody.localCount = 1; var constructor:MethodInfo = new MethodInfo(); method.methodBody.initScopeDepth = 1; constructor.methodName = "org.Conferences/:Conferences"; method.methodBody.maxScopeDepth = 2; constructor.returnType = new QualifiedName("*", LNamespace.ASTERISK); method.methodBody.maxStack = 2; constructor.methodBody = new MethodBody(); method.methodBody.opcodes.push(Opcode.getlocal_0.op()); constructor.methodBody.localCount = 1; method.methodBody.opcodes.push(Opcode.pushscope.op()); constructor.methodBody.initScopeDepth = 1; method.methodBody.opcodes.push(Opcode.pushstring.op(["360|Flex!"])); constructor.methodBody.maxScopeDepth = 2; method.methodBody.opcodes.push(Opcode.returnvalue.op()); constructor.methodBody.maxStack = 1; trait = new MethodTrait(); constructor.methodBody.opcodes.push(Opcode.getlocal_0.op()); trait.traitKind = TraitKind.METHOD; constructor.methodBody.opcodes.push(Opcode.pushscope.op()); method.as3commonsByteCodeAssignedMethodTrait = trait; constructor.methodBody.opcodes.push(Opcode.getlocal_0.op()); instanceInfo.methodInfo.push(method); constructor.methodBody.opcodes.push(Opcode.constructsuper.op([0])); var scriptInfo:ScriptInfo = new ScriptInfo(); constructor.methodBody.opcodes.push(Opcode.returnvoid.op()); var scriptInitializer:MethodInfo = new MethodInfo(); var trait:MethodTrait = new MethodTrait(); scriptInfo.scriptInitializer = scriptInitializer; trait.traitKind = TraitKind.METHOD; scriptInitializer.methodName = ""; constructor.as3commonsByteCodeAssignedMethodTrait = trait; scriptInitializer.returnType = new QualifiedName("*", LNamespace.ASTERISK); instanceInfo.addTrait(trait); scriptInitializer.methodBody.opcodes.push(Opcode.getlocal_0.op()); instanceInfo.constructor = constructor; scriptInitializer.methodBody.opcodes.push(Opcode.pushscope.op()); var staticConstructor:MethodInfo = new MethodInfo(); scriptInitializer.methodBody.opcodes.push(Opcode.getscopeobject.op([0])); staticConstructor.methodName = "org.Conferences:Conferences:::Conferences$cinit"; var mn:QualifiedName = new QualifiedName("Conferences", new LNamespace(NamespaceKind.PACKAGE_NAMESPACE, staticConstructor.returnType = new QualifiedName("*", LNamespace.ASTERISK); "org")); staticConstructor.methodBody = new MethodBody(); scriptInitializer.methodBody.opcodes.push(Opcode.findpropstrict.op([mn])) // staticConstructor.methodBody.localCount = 1; scriptInitializer.methodBody.opcodes.push(Opcode.getproperty.op([mn])); staticConstructor.methodBody.initScopeDepth = 1; scriptInitializer.methodBody.opcodes.push(Opcode.pushscope.op()); staticConstructor.methodBody.maxScopeDepth = 2; scriptInitializer.methodBody.opcodes.push(Opcode.popscope.op()); staticConstructor.methodBody.maxStack = 1; scriptInitializer.methodBody.opcodes.push(Opcode.newclass, [classInfo]); staticConstructor.methodBody.opcodes.push(Opcode.getlocal_0.op()); scriptInitializer.methodBody.opcodes.push(Opcode.initproperty, [mn]); staticConstructor.methodBody.opcodes.push(Opcode.pushscope.op()); scriptInitializer.methodBody.opcodes.push(Opcode.returnvoid); staticConstructor.methodBody.opcodes.push(Opcode.returnvoid.op()); abcFile.addClassInfo(classInfo); var classInfo:ClassInfo = new ClassInfo(); abcFile.addScriptInfo(scriptInfo); classInfo.staticInitializer = staticConstructor; abcFile.addInstanceInfo(instanceInfo);
  • 31. Generate a class with the emit API var abcBuilder:IAbcBuilder = new AbcBuilder(); var classbuilder:IClassBuilder = abcBuilder.defineClass("org.Conferences"); var methodBuilder:IMethodBuilder = classbuilder. defineMethod("myFavoriteConference"); methodBuilder.returnType = "String"; methodBuilder.addOpcode(Opcode.getlocal_0) .addOpcode(Opcode.pushscope) .addOpcode(Opcode.pushstring,["360|Flex!"]) .addOpcode(Opcode.returnvalue);
  • 32. Loading the class into the AVM abcBuilder.addEventListener(Event.COMPLETE, loadedHandler); abcBuilder.buildAndLoad(); function loadedHandler(event:Event):void { var clazz:Class = ApplicationDomain.currentDomain.getDefinition ("org.Conferences") as Class; var instance:* = new clazz(); var result:String = instance.myFavoriteConference(); // result == '360|Flex!' }
  • 33. The feeling after this finally works...
  • 34. ProxyFactory: Generating proxy var factory:IProxyFactory = new ProxyFactory(); factory.defineProxy(Conferences); factory.generateProxyClasses(); factory.addEventListener( ProxyFactoryEvent.GET_METHOD_INVOCATION_INTERCEPTOR, onProxyCreate); factory.addEventListener(Event.COMPLETE, onComplete); factory.buildAndLoad(); function onComplete(event:Event):void { var conf:Conference = factory.createProxy(Conference); // This will return the proxy class instance! }
  • 35. ProxyFactory: Injecting interceptors function onProxyCreate(event:ProxyFactoryEvent):void { var interceptor:IMethodInvocationInterceptor = createInterceptor(); event.methodInvocationInterceptor = interceptor; } function createInterceptor():IMethodInvocationInterceptor { var result:IMethodInvocationInterceptor = new BasicMethodInvocationInterceptor(); //register IInterceptors... }
  • 36. IInterceptor interface public interface IInterceptor { function intercept(invocation:IMethodInvocation):void; }
  • 37. IMethodInvocation interface public interface IMethodInvocation { function get kind():InvocationKind; function get targetInstance():Object; function get targetMember():QName; function get targetMethod():Function; function get arguments():Array; function get proceed():Boolean; function set proceed(value:Boolean):void; function get returnValue():*; function set returnValue(value:*):void; }
  • 38. So, how to build an AOP framework? ● ABC - I hate myself and I want to die ● AbcBuilder - I think the emit API sucks ● Emit API - I think the proxy API sucks ● Proxy API - I love AS3Commons-Bytecode! Pick your poison!
  • 40. AS3Commons AOP Advice interfaces (some of them) - IMethodBeforeAdvice beforeMethod(method:Method, args:Array, target:*):void; - IConstructorAfterAdvice afterConstructor(constructor:Constructor, args:Array, target:*):void; - ISetterAroundAdvice beforeSetter(setter:Accessor, target:*, value:*):void; afterSetter(setter:Accessor):void; afterSetterThrows(setter:Accessor, value:*, target:*, error:Error):void;
  • 41. AS3Commons AOP Advisor Combines Pointcut (when) and Advice (what). Actually, Advice is always wrapped in an Advisor: // in AOPProxyFactory... public function addAdvice(advice:IAdvice, target:*=null):void { addAdvisor(new AlwaysMatchingPointcutAdvisor(advice), target); }
  • 42. AS3Commons AOP Adding an advisor to the proxy factory (1/2) var factory:AOPProxyFactory = new AOPProxyFactory(); var pointcut:IPointcut = new MethodNameMatchPointcut(["getSecretData"," getMoreSecretData"]); var advice:IAdvice = new AuthenticationAdvice(); factory.addAdvisor(new PointcutAdvisor(pointcut, advice));
  • 43. AS3Commons AOP Adding an advisor to the proxy factory (2/2) The AuthenticationAdvice can now be simplified: public function beforeMethod( method:Method, args:Array, target:*):void { if (method.name == "getSecretData" || method.name == "getMoreSecretData") { if (!userIsAuthorized) { throw new Error("User is not authorized"); } } } }
  • 44. AS3Commons AOP Pointcuts - Name matching - Regular expression matching - Binary: combine pointcuts (and, or, ...)
  • 45. AS3Commons AOP Interceptors Use an interceptor if you want full control over the execution of the advice code. public class StringToUppercaseSetterInterceptor implements ISetterInterceptor { function interceptSetter(invocation:ISetterInvocation) { if (invocation.value is String) { invocation.value = invocation.value.toUpperCase(); } invocation.proceed(); } }
  • 46. AS3Commons AOP AOPProxyFactory Configure it with advice, advisors and/or interceptors and get proxies from it. var factory:AOPProxyFactory = new AOPProxyFactory(); factory.target = MyService; factory.addAdvice(new AuthorizationAdvice()); ... (asynchronous loading of the factory) var service:MyService = factory.getProxy(); Hides Bytecode's ProxyFactory interceptor details.
  • 47. AS3Commons AOP AOPBatchProxyFactory Proxy factory to create multiple proxies. Used inside the AOPProxyFactory. Uses AS3Commons-Bytecode to generate the proxies. The interceptor we create is an AdvisorInterceptor.
  • 48. AS3Commons AOP AdvisorInterceptor see Chain of Responsibility design pattern When using an interceptor, call the proceed() method on the interceptor if you want to move down the chain. If not, the chain will be ended. The framework does this for you when using Advice/Advisors. Easier, but less control.
  • 49. AS3Commons AOP What's to come and what is possible? - Pointcut dialect & metadata/annotation driven pointcut configuration - Integration with Spring ActionScript or other Dependency Injection frameworks
  • 50. More info www.as3commons.org ActionScript Virtual Machine 2 Spec: http://www.adobe. com/content/dam/Adobe/en/devnet/actionscript/articles/avm2 overview.pdf Twitter @mechhead, @herrodius, @as3commons, @stackandheap