HowToUseCairngormModule

There is a newer version of this page. You can find it here.

How to use the Cairngorm Module Library (Requires Parsley)

Contents

Summary

The Cairngorm Module library is designed to simplify the configuration, rendering and loading of modular content. Additonally it offers flexiblity to communicate to modules. It contains infrastructure classes, view components, a mechanism for loading and communicating to modular content on-demand in response to Parsley messages.

Introduction

The biggest benefit of modularization we see is often not the reduced initial SWF size, although that is a benefit, but rather the development efficiency and encapsulation of functional areas. A module can be developed, tested and profiled in relative isolation by a small group of developers, and the contracts can be agreed between modules. Build times are quick and one module can effectively offer services to another. The implementation of one module can change without impact on others. This approach can scale to large delivery teams.

The Flex SDK provides a ModuleLoader view component for placing modular content in-line with other views. The ModuleManager singleton offers a manual management of modules. The IModuleInfo interface abstracts the loading and unloading of modular content.

The Cairngorm Module library provides additional features on top of the Flex SDK and Parsley module support:

  • Declaration of module configuration externally, so the URLs for modules might be declared in MXML or loaded at runtime from an XML file.
  • Lazy loading of modules in response to application messages. For example, a StartChatMessage is sent, so the Chat module needs to be loaded and initialized, then the StartChatMessage processing can resume.
  • Routing of messages to the appropiate modules (i.e. communicating to all modules, all modules of one type, or a specific module instance)

Configuration

The ParsleyModuleDescriptor can be used to describe the location and application domain of the module. This can be specified in a Parsley MXML or XML context.

Compile-Time MXML Configuration

When configuring the module library via MXML, use the CairngormModuleSupport ContextBuilder when creating the Parsley context:

<spicefactory:ContextBuilder>
    <cairngorm:CairngormModuleSupport/>
    <spicefactory:FlexConfig type="{ CairngormModuleLibSampleContext }"/>
</spicefactory:ContextBuilder>

Then, describe the module in the MXML context:

<cg:ParsleyModuleDescriptor objectId="moduleA"
                            url="example/moduleA/ModuleA.swf"
                            applicationDomain="{ ClassInfo.currentDomain }"/>
Run-Time XML Configuration

When configuring the module library via XML that can be loaded at runtime, use the CairngormModuleXMLSupport additionally to the CairngormModuleSupport ContextBuilder when creating the Parsley XML context:

<spicefactory:ContextBuilder>
    <cairngorm:CairngormModuleSupport/>
    <cairngorm:CairngormModuleXMLSupport/>
    <spicefactory:XmlConfig file="runtimeContext.xml"/>
</spicefactory:ContextBuilder>

Then, describe the module in the XML context:

<objects xmlns="http://www.spicefactory.org/parsley"
         xmlns:cairngorm="http://www.adobe.com/cairngorm"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.spicefactory.org/parsley
                http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd">

    <cairngorm:parsley-module-descriptor object-id="moduleA"
                                         url="example/moduleA/ModuleA.swf"/>

</objects>

Rendering and Loading

Rendering

In order to reference a definition of a module you need to take the objectId of a ParsleyModuleDescriptor...

<cg:ParsleyModuleDescriptor objectId="moduleA"
                            url="example/moduleA/ModuleA.swf"/>

...and connect it with an IModuleManager instance defined in the view that loads the module.

<mx:Script>
    <![CDATA[
        import com.adobe.cairngorm.module.IModuleManager;

        [Inject(id="moduleA")]
        public var moduleManager:IModuleManager;
    ]]>
</mx:Script>

<mx:Label text="moduleId: { moduleId == null ? 'NOT SET' : moduleId }"/>

<module:ModuleViewLoader moduleManager="{ moduleManager }"
                         skinClass="com.adobe.cairngorm.module.ModuleViewLoaderSkin">
    <module:loadPolicy>
        <module:BasicLoadPolicy/>
    </module:loadPolicy>
</module:ModuleViewLoader>

As soon as the IModuleManager implementation is injected into the view, (which would be the DisplayObject's addedToStage event following the default of Parsley), the module starts loading through the ModuleViewLoader component. The skinClass property allows to define the visual display during the module loading and error state, which is likley to be custom to most applications.

For Flex 3, you can use a ViewLoader component like the below

<module:ViewLoader moduleManager="{ moduleManager }">
    <module:loadPolicy>
        <module:BasicLoadPolicy/>
    </module:loadPolicy>
</module:ModuleViewLoader>

Since we migrated our library to support Flex 4, we did refactor the ViewLoader to mimic the SDK4 new ModuleViewLoader in order to support LoadPolicy but now the ViewLoader do not support states for loading and error. If you want to have different states we suggest that you move to SDK4 and use ModuleViewLoader or you can subclass the ViewLoader to add these behaviors which is likely to be custom to most applications in any case.

Lazy Loading - Sending an Event to a Module

When events need to be send to modules using Parsley messaging, the modules need to be loaded and initialized in order to receive Parsley events. The module library takes care of the lazy loading in case the module isn't ready yet to receive the event.

The user needs to define the event in inside the context with a ModuleMessageInterceptor definition. For example, the following loads the module defined in the ParsleyModuleDescriptor from above with the objectId "moduleA", once the user dispatches a BroadcastMessage event.

<cg:ModuleMessageInterceptor type="{ BroadcastMessage }"
                             moduleRef="moduleA"/>

Behind the scences the module library intercepts the message until the loading is complete and proceeds the dispatching process once the module is ready to receive the message (loaded and instantiated with a Parsley context that can receive it).

For the loaded module to receive the message the module needs to implement the IParsleyModule interface, which points to the Parsley context that can receive the message (using a Parsley MessageHandler).

<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"            
           xmlns:spicefactory="http://www.spicefactory.org/parsley"
           implements="com.adobe.cairngorm.module.IParsleyModule" >

    <mx:Script>
        <![CDATA[
        import com.adobe.cairngorm.module.IParsleyModule;            
        import org.spicefactory.parsley.flex.FlexContextBuilder;

        public function get contextBuilder():ContextBuilderTag
        {
        return contextBuilderTag;
        }                  
        ]]>
    </mx:Script>

    <spicefactory:ContextBuilder id="contextBuilderTag" 
                                 config="{ ModuleAContext }" />

Now, any object within the ModuleAContext can accept the module message like this:

[MessageHandler(scope="local")]
public function broadcastMessageHandler(message:BroadcastMessage):void
{

Communication Options to Module Instances

The relationship between a module definition and a module view does not have to be 1:1. Applications can for example display multiple instances of one module. The module library allows to control the communication between the loader and one or many module definitions and one or many module instances.

Dispatching a Message to All Instances of One Defintion

The ModuleMessageInterceptor from above...

<cg:ParsleyModuleDescriptor objectId="moduleA"
                            url="example/moduleA/ModuleA.swf"/>

<cg:ModuleMessageInterceptor type="{ BroadcastMessage }"
                             moduleRef="moduleA"/>

...directs every BroadcastMessage to all module instances from the definition "moduleA".

Dispatching a Message to All Instances of All Defintions

The below message is being directed to all instances of all module definitions.

<cg:ModuleMessageInterceptor type="{ ClearLogMessage }"/>
Dispatching a Message to One Instance of One Definition

In order to dispatch to one particular instance of one module definition, the ModuleMessageInterceptor searches for a property annotated with a ModuleId definition....

<cg:ModuleMessageInterceptor type="{ PingMessage }"/>

...which can be defined inline:

public class PingMessage
{
    private var _moduleId:String;

    public function PingMessage(moduleId:String)
    {
        this._moduleId=moduleId;
    }

    [ModuleId]
    public function get moduleId():String
    {
        return _moduleId;
    }
}

The value of this ModuleId property must be defined on the ViewLoader component's moduleId property.
For more information, please view the examples within the ModuleTest project.

### Cairngorm 3 - [ Home ][1] - [ Guidelines ][3] - [ Tools ][4] - [ Libraries Downloads ][2]
### Cairngorm 2 - [ Home ][5] - [ Framework Downloads ][6] - [ Eclipse Plugin ][7]
### Project - [ Source ][8] - [ Bug Database ][9] - [ Submitting a Patch ][10] - [ Developer Documentation ][11] - [ Forums ][12] - [ License ][13]