Many theories were written lately about the presentation model. There are many advantage of using the presentation model and you can read about it in Paul William’s blog talking about the different ways to implements the presentation model. You can also download David Deraedt sample application which is called Caringorm application but is not really using the Caringorm framework and he is asking more questions that really have a working example. So I feel that what is really missing is a real POC example. I decided to create a simple example as well as create the custom Ant scripts to automate the process, so we don’t need to keep doing the same thing every time we start a Cairngorm application. This type of Ant script can turn into a framework but I am sure there are still improvement to be made to get it perfected.
The idea is basically to move to a TDD development cycle. TDD is much better than the usual methodology of creating some kind of UML diagrams based on business rules which already includes design patterns. The reason is that business rules keep changing and you may find yourself with a large application and many design patterns to do a simple logic. TDD also forces us to think about every business rule and make sure everything is clear as well as making sure we have what we need and nothing more. TDD also allow us to show results right away.
Using TDD we can generate a simple unit test class, which of course will fail and then we can start implementing the methods until it passes. At this point we don’t care about the code that much but more about passing the test. Once we pass the test and got a green light we can start creating our classes and refactor when needed, for instance replacing “if..else” statements into design patterns when needed.
I believe that working under TDD development cycle can save time in the long run. Once we need to make changes, due to new business rules, we don’t have to worry if the code we added broke previous code and we can just run the test suite to test the entire application.
The example is very simple in nature it loads a module with label field after the services have completed. To view and download the complete example click here.
I believe that using the presentation model is a key in order to create an efficient Test Driven Development (TDD) development cycle. The application logic is separated from the view can be easily tested by unit testing, which can be packages into Unit Suites. The future release of Flex 4 it will be easy to create Unit testing and Test suite classes right from the menu. I am also considering creating the unit testing class automatically to fit Cairngorm presentation model.
The example here is a Caringorm example that is simple in nature and easy to understand. I also updated Cairngen to allow us to a creation of a basic skeleton to implement the presentation model using Ant scripts.
The Ant scripts creates the main entry point to the application “main.mxml” as well as set the model locator to be a locator and not a data holder for the application data.

The new scaffolding will generate the domain, presentation folders under the model package with the following classes:
* LibraryModel.as
* AbstractPM.as
* MainPM.as
I also implemented the flash-ThunderBolt on the commands so it will log in a message every time a command is executed in firebug. You can read about it in my previous blog. Additionally, commands that include delegate should be under Services in command structure so it will be easy to find all the commands related to services.
The ant scripts has issues with Mac OS X since the Mac is missing the Java 1.6 Jars that are needed so I added them under “libs”. So you can easily place them under the “plugin” folder in Eclipse and be up and running quickly.
Feel free to download the updated Cairngen Ant tool with these changes from here.
Please note that the Jars, Flash-ThunderBolt, Cairngorm, Cairngen etc are under copyright and refer to each tool to find out the license agreement.
Let’s create an example. I want to go over with you a simple example that loads a module into our main application, after a service called is made. I simulated a service call by using a timer delay, and I tried to keep this example as simple as possible so you can understand the concept.
Let’s get started. First generate all the scaffolding using the ANT script. Next, we need to create our module which will have a simple label field. I called it FirstModule.mxml
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="300">
<mx:Script>
<![CDATA[
import com.elad.application.model.ModelLocator;
[Bindable]
private var modelLocator:ModelLocator = ModelLocator.getInstance();
]]>
</mx:Script>
<mx:Label text="{modelLocator.firstModule.text}" />
</mx:Module>
The text is bindable to the firstModule and notice that it is bindable to the ModelLocator, make sure you add a reference in the model locator.
public static function getInstance() : ModelLocator
{
if ( instance == null )
{
instance = new ModelLocator( new Private() );
instance.libraryModel = new LibraryModel();
instance.mainPM = new MainPM( instance.libraryModel );
instance.firstModule = new FirstModulePM( instance.libraryModel );
}
return instance;
}
Notice that in component implementation we could have just passed the presentation model class instance instead of calling the model locator.
In the main.mxml we can now place the module and the rest of the class was generated automatically for you through the Ant script. There is a call to the presentation model pre-initialize and all the logic is done in the presentation model.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
xmlns:business="com.elad.application.business.*"
xmlns:control="com.elad.application.control.*"
xmlns:view="com.elad.application.view.*"
preinitialize="modelLocator.mainPM.preinitialize()">
<mx:Script>
<![CDATA[
import com.elad.application.model.ModelLocator;
[Bindable]
private var modelLocator:ModelLocator = ModelLocator.getInstance();
]]>
</mx:Script>
<control:testController />
<business:Services />
<mx:ModuleLoader url="{modelLocator.mainPM.MODULE_URL}" />
</mx:Application>
Let’s take a look at the presentation model for the main class. The presentation model was created for you with the Ant script and you need to implement the methods. Take a look at the abstract presentation model, which was also generated automatically for you. I basically took David Deraedt’s class and changes it as well as added more methods since the his abstract class didn’t count for pre-initialized and initialized as a common application will need and other methods that I think are common in real life applications.
/*
Copyright (c) 2008 Elrom LLC, Inc. All Rights Reserved
@author Elad Elrom
@contact elad.ny@gmail.com
@project POC project
@internal
*/
package com.elad.application.model.presentation
{
import flash.events.Event;
import flash.events.EventDispatcher;
/**
* Abstract class to include the first time the class run as well as the subsequent init of the class
* Also included initialize methods and handler to be used in the view.
*
*/
public class AbstractPM extends EventDispatcher
{
/**
*
* Define a var to store weather the application state was shown already
*
*/
private var firstShow:Boolean = true;
/**
*
* Default constructor
*
*/
public function AbstractPM()
{
}
/**
* Method to handle first show of the application
*
*/
public function handleShow():void
{
if( firstShow )
{
handleFirstShow();
firstShow = false ;
}
else handleSubsequentShows();
}
/**
* Method to be called on preinitialize
*
*/
public function preinitialize():void
{
handlePreInitialize();
}
/**
* Method to be called on initialize
*
*/
public function initialize():void
{
handleInitialize();
}
/**
* Method to handle preinitialize
*
*/
protected function handlePreInitialize():void
{
// to be overriden
}
/**
* Method to handle initialize of the application
*
*/
protected function handleInitialize():void
{
// to be overriden
}
/**
* Method to handle the view once preinit and init is completed
*
*/
protected function handleCompleted():void
{
// to be overriden
}
/**
* Method to implement first show of the application
*
*/
protected function handleFirstShow():void
{
// to be overriden
}
/**
* Method to handle dubsequent shows of the application
*
*/
protected function handleSubsequentShows():void
{
// to be overriden
}
/**
* Method invoke once the Initialize is completed.
*
* @param event
*
*/
public function preInitializeCompletedHandler(event:Event):void
{
handleInitialize();
}
/**
* Method invoke once the Initialize is completed.
*
* @param event
*
*/
public function initializeCompletedHandler(event:Event):void
{
handleShow();
}
}
}
The abstract class is pretty self explanatory, but feel free to ask questions if you are having hard time understanding it. Moving forward to the MainPM we need to implement the methods and add some logic. The handler for the pre initialized listen to the “PreInitializationCommandCompleted” event (which was also created automatically for you), it than call the “StartupServicesEvent” which will make all the service calls, but in our simulated case just use the counter to delay the application. After the startup services are done we can move to the initialize method “handleInitialize”, which listen to the “InitializationCommandCompleted” event and in our case we don’t need to do anything so we just dispatched that event, but in real life application you can use that to apply all kind of logic to your application.
After the event is fire it will be sent to the “handleShow” method in the abstract class, which will decide if it the first time the application is used and sent to the “handleFirstShow” or after that sent to “handleSubsequentShows” method, in our case I wanted to keep it simple so they both just go to the “handleCompleted” method, which set the module URL: MODULE_URL = “FirstModule.swf” and starts the module.
/*
Copyright (c) 2008 Elrom LLC, Inc. All Rights Reserved
@author Elad Elrom
@contact elad.ny@gmail.com
@project POC project
@internal
*/
package com.elad.application.model.presentation
{
import com.adobe.cairngorm.control.CairngormEventDispatcher;
import com.elad.application.events.InitializationCommandCompleted;
import com.elad.application.events.PreInitializationCommandCompleted;
import com.elad.application.events.StartupServicesEvent;
import com.elad.application.model.ModelLocator;
import com.elad.application.model.domain.LibraryModel;
import mx.logging.Log;
import org.osflash.thunderbolt.ThunderBoltTarget;
[Bindable]
/**
*
* Defines the <code>MainPM<code> Value Object implementation
*
*/
public class MainPM extends AbstractPM
{
/**
*
* Define an instance of <code>ThunderBoltTarget</code>
*
* @see org.osflash.thunderbolt.ThunderBoltTarget
* @see mx.logging.Log
*
*/
private var _target:ThunderBoltTarget = new ThunderBoltTarget();
/**
*
* Define an instance of the <code>PagesPM</code>
*
*/
var firstModulePM:FirstModulePM;
/**
*
* Define an instance of the <code>LibraryModel</code>
*
*/
public var libraryModel:LibraryModel;
/**
*
* Define moduale URL for used with Modules
*
*/
public var MODULE_URL:String = "";
/**
* Defualt constractor set the <code>LibraryModel</code>
* @param LibraryModel
*
*/
public function MainPM(libraryModel:LibraryModel)
{
this.libraryModel = libraryModel;
firstModulePM = new FirstModulePM(libraryModel);
}
/**
* Method to handle first show of the application
*
*/
override protected function handlePreInitialize():void
{
// set filter for logging API and inject thunder bolt
_target.filters = ["com.elad.application.commands.*"];
Log.addTarget(_target);
// track once pre-initialize completed
CairngormEventDispatcher.getInstance().addEventListener( PreInitializationCommandCompleted.COMPLETED, preInitializeCompletedHandler );
// call startup services
new StartupServicesEvent().dispatch();
}
/**
* Method to handle first show of the application
*
*/
override protected function handleInitialize():void
{
// track once initialize completed
CairngormEventDispatcher.getInstance().addEventListener( InitializationCommandCompleted.COMPLETED, initializeCompletedHandler );
new InitializationCommandCompleted().dispatch();
}
/**
* Method to handle first show of the application
*
*/
override protected function handleFirstShow():void
{
// implements or leave default
handleCompleted();
}
/**
* Method to handle dubsequent shows of the application
*
*/
override protected function handleSubsequentShows():void
{
// implements or leave default
handleCompleted();
}
/**
* Method to handle the view once preinit and init are completed
*
*/
override protected function handleCompleted():void
{
// remove event listeners
CairngormEventDispatcher.getInstance().removeEventListener( PreInitializationCommandCompleted.COMPLETED, preInitializeCompletedHandler );
CairngormEventDispatcher.getInstance().removeEventListener( InitializationCommandCompleted.COMPLETED, initializeCompletedHandler );
// implements changes in view
MODULE_URL = "FirstModule.swf";
}
}
}
View and download the complete example from here





















