Avoiding pitfalls of Flex RSL with Self Initialized Libraries

Flex RSLs are notoriously naive in regards to dynamic object instantiation. Consider the following code snippet when the actual class descends Panel or it is a remoting DTO with the [RemoteClass] annotation:
[quickcode:noclick]var className:String = “some.flex.class”;
var clazz : Class = loaderInfo.applicationDomain.getDefinition(className) as Class;
var instance: Object = new clazz();
[/quickcode]
In either case, well being of the class is based on mixins – decorator classes generated by Flex compiler. Mixins carry obligatory init(o:Object/*systemManager or moduleFactory*/) method and get called to decorate startup class of the application (SystemManager) or the module (ModuleFactory). For instance, a class with [RemoteClass("foo.Bar")] annotation contributes a similar looking fragment to the mixin class _YourApplicationName_FlexInit:

  try {
      if (flash.net.getClassByAlias("foo.Bar") == null){
          flash.net.registerClassAlias("foo.Bar", flex.class.with.RemoteClassAnnotation);}
  } catch (e:Error) {
          flash.net.registerClassAlias("foo.Bar", flex.class.with.RemoteClassAnnotation); }

Similarly, a class that descends from a Panel depends on mixin [_YourApplicationName]_Styles to carry the following:
        .  .  .
        // spark.components.Panel
        selector = new CSSSelector("spark.components.Panel", conditions, selector);
        mergedStyle = styleManager.getMergedStyleDeclaration("spark.components.Panel");
        style = new CSSStyleDeclaration(selector, styleManager, mergedStyle == null);
        . . .

Now, here is the problem. If you hide your class behind getDefinition() Flex compiler does not contribute to either _FlexInit or _Styles mixins. In other words, your RSL may contain 100 classes, all of them will be loaded, but they will be lacking proper initialization if you did not explicitly reference them in the application.


Problem Illustration

Let’s illustrate. On the left is the application that on button click … fails to dynamically instantiate a custom panel from standard Flex RSL. On the right we show working application AFTER the solution has been applied (Patience, reader, patience!)
Sample application with problem before and after treatment
Here is the application code:

  <![CDATA[
      import mx.core.IVisualElement;
      private var visualElement:IVisualElement;
      //import spark.components.Panel;Panel; // That would be too simple :)
      private function createComponent(componentName:String) : void {
        var clazz : Class = loaderInfo.applicationDomain.getDefinition(componentName) as Class;
        visualElement = IVisualElement(new clazz() );
        addElement(visualElement);
      }
  ]]>


The very custom panel is hosted by a separate Flex Library Project – ComponentLibrary:
    public static var count:int;
       [Bindable] private var instanceNumber:int;

Make sure the link type of the ComponentLibrary is set to “RSL”. Run the application, click on the Button – you won’t see any panels. Better yet, Debug (instead of Run) and you will notice console trace statements of the panels actually being created. However, custom panel is not shown, because _Styles mixin lacks section for ancestor – Spark Panel.


Solution

So what is the solution? Obviously, the Adobe RSL SWF has to be replaced by something else. By default, ComponentLibrary.swf get extracted from ComponentLibrary.swc on every build of the application. But, if we turn off the “AutoExtract” checkbox, we are free to replace it with the SWF of our own making. Which one? A sub-application SWF. Instead of a headless, single framed RSL SWF, we will use double framed application SWF adding a descendant of the mx.core.SimpleApplication as a head class. Within such head class we can statically reference all library classes. As a result, compiler will generate required mixins within the “library” SWF. That is why in Farata we coined the term self-initialized library, meaning that classes in our library do not need external initialization by the Flex compiler:


package {
  import mx.core.SimpleApplication;
  public class LibraryHead extends SimpleApplication {

        // List all library classes here, so Flex compiler will take care of them
        import  com.farata.samples.CustomPanel;com.farata.samples.CustomPanel; 

  public function LibraryHead() {
    // Custom library initialization code may go here
    trace("Self-initialized library has been loaded");
  }
}
}

As a matter of fact, the last drop required to force Flex compiler into mixin generation is to use a MXML extension of the LibraryHead as the compilation target:

Importantly, we use Ant scripts to build self-initialized libraries, since out of the box Flex library project is not positioned to produce SWFs:

Wait! There is more. In Flex 3 making and using self-initialized library would be enough. In Flex 4, however, we have to replace single line of code that applies the mixins in the mx.core.FlexModuleFactory, ancestor of the SimpleApplication. In place of
[quickcode:noclick]
c["init"](this);
[/quickcode]
we should put more sophisticated code that instead of decorating the factory class of the loaded library decorates the factory class of the entire application, i.e. SystemManager:

var mixinTarget:Object;
   if (this is FlexApplicationBootstrap) //aka self initialized library
    mixinTarget = SystemManagerGlobals.topLevelSystemManagers[
                     SystemManagerGlobals.topLevelSystemManagers.length-1
                ];
   else
                mixinTarget = this;
   c["init"](mixinTarget);

Add this class to the application sources and … it won’t be considered by the SWF. For one thing, if you did not explicitly reference a variable of this class (or use -includes compiler switch) it will not make into SWF at all. Even if you did, however, remember that Flex SWF links the minimal number of classes to the first frame (FlexModuleFactory is NOT among them) and all the rest – to the second. In between (actually – under the control of the first frame’s code) Flex dynamically loads classes from RSLs, starting from signed RSLs and ending with your custom ones. By the time ComponentLibrary.swf get loaded, class definition of the mx.core.FlexModuleFactory will already be grabbed from “earlier” framework.swc. That’s a known challenge of Flex “monkey patching”. The simplest way to overcome it is to overlap application sources with one of the classes that Flex must put in the first frame. It can be custom preloader or mx.core.SystemManager itself, however, in this context we prefer mx.core.RSLListLoader. Simply, add import mx.core.FlexModuleLoader;mx.core.FlexModuleLoader; anywhere in the modified mx.core.RSLListLoader and add it to the source path of your main application along with the modified FlexModuleFactory. Again, we use it to our advantage that all dependancies of SystemManager, including RSLListLoader get linked to the first frame:
    import mx.core.FlexModuleFactory; mx.core.FlexModuleFactory; // WE ADDED THIS
    public function RSLListLoader(rslList:Array)
    {
      super();
        this.rslList = rslList;
    }

Believe it or not, that’s it.

Here is the summary of the steps:
1. Turn-off “autoextract” of the SWC
2. Create self-initialized library SWF and place it into bin or bin-debug
3. Add monkey-patched FlexModuleFactory and RSLListLoader into Flex sources
4. Say good-bye to plain old Flex RSLs.

I’d like to use this opportunity and invite Flex developers living in Europe to attend our Advanced Flex Master Class in Brussels, Belgium on March 1 and 2, 2010.

Victor Rasputnis

6 thoughts on “Avoiding pitfalls of Flex RSL with Self Initialized Libraries

  1. Very interesting stuff :)

    Does this mean components need to explicitly list ALL used libraries down to the actual class and not just widcard namespace?

    Seems like
    import com.farata.samples.CustomPanel;com.farata.samples.CustomPanel;

    could become quite a lengthy import/usage statement for some components.

    Does this also imply that all child components would need to follow this explicit import method or is this typically used for top level wholistic components?

  2. Tom,

    Yes, ALL dependencies, direct and indirect must be referenced, as long as these dependencies depend on mixins.
    It’s the “Achilles heel” of RSL, by design.

    Then again, who needs dynamic class invocation? ;)

    Victor

  3. Victor-

    Your blog is inspiring.

    I am using BlazeDS on initialization of my app. I make 3 – 10 second RemoteObject calls (concurreny=multiple)…..hoping that it will be asyncromous and take justover 10 seconds. Instead is takes 30 seconds.

    Can you tell me if there is a way to get around the batching of RO calls by Flex/BlazeDS so they are truely asyncronous and “parallel”???

    thanks for any insight! Chuck

  4. @Chuck Recently, we were hired to fix a situation in an application, where a user could initiate several remote calls from Flex to BlazeDS, and each call was invoking a lengthy DB processing (a stored procedure). The application was crawling.

    We’ve resolved that issue by replacing an off-the-shelf BlazeDS adapter with a custom one. But that solution has nothing to do with the batching.

  5. Victor!

    I purchased the book, Enterprise development with flex and I tried creating the Self Initialized Library sample using Flex 4, spark, I followed all the steps mentioned in your book and updated the steps for flex 4 spark as mentioned in your blog but i am not able to see my spark Panel, I modified FlexModuleFactory.as and RSLListloader.as in flex4 sdk, but no success…..please help me….i used flex2Ant nightly builds to create my own library swf……can you send me the sample for flex 4 spark………

    thanks
    Rishi

  6. Victor!

    Thanks for the guidance, I am now able to load flex 4 self initialized RSLs.

    It works perfect….

Comments are closed.