This page is an archive of my old blog. Please visit DavidTucker.net for my current blog.
This site is no longer being maintained and commenting is disabled.

Getting Started with Cairngorm – Part 3

Now that you have isolated two specific elements of the Cairngorm Micro-Architecture, you will now create a more complete Cairngorm application. Up to now the tutorials have covered only one design pattern, the ModelLocator, but now you will be introduced to the most crucial element of Cairngorm, the Service to Worker design pattern. The explanation of this pattern will span two tutorials. This tutorial will cover the basic flow inside of a Cairngorm application, and the next tutorial will expand this flow to include server interaction. However, before you can properly implement this design pattern you need to learn about the organization of a Cairngorm project.

Organizing a Cairngorm Project

One of the tasks involved with any project is organization. When working with other developers, this becomes extremely important. Normally a Cairngorm project is organized in the following manner:

  • There is a Main.mxml file that is the main application file for the Cairngorm application.
  • The project files are contained in a folder that uses "reverse-dns" format. For example, if the project was named CairngormSample, I would use the following folders net/davidtucker/CairngormSample .
  • Within the CairngormSample directory, there will be the following folders (there will be additional folders added in the next tutorial).
    • events/ - This directory holds all of the custom events for the application
    • control/ - This directory houses the FrontController for the application
    • commands/ - This directory contains the Commands that are called by the FrontController
    • model/ - The ModelLocator is contained in this folder (and other classes related to the model)
    • view/ - The components of the view are contained in this directory

By following this standard, you can know where to find any class that you may need in your Cairngorm application. Figure 1 illustrates this project structure. It also is a good development process to have a standard organizational structure for your projects - even if you are not using Cairngorm.

Cairngorm Project Folder

Figure 1 - Cairngorm Project Structure

The Service to Worker Pattern

The Service to Worker pattern is the hardest for most people to grasp. It encompasses most of the logic for a Cairngorm application. To understand this pattern, you will need to understand some of the classes that are included with Cairngorm and their respective purposes.

  • CairngormEvent [Reference] - CairngormEvent is central in this pattern. It extends from Event. For your event to be handled properly in Cairngorm, it will need to be of type CairngormEvent.
  • CairngormEventDispatcher [Reference] - CairngormEventDispatcher actually dispatches the CairngormEvents. It is a singleton (just like the ModelLocator). In previous Cairngorm versions, you would call this class regularly, but now CairngormEvents can dispatch themselves (via the method dispatch). This method is simply a wrapper for the CairngormEventDispatcher, so even if you don't actually import and call the class, it is still central to the Service to Worker pattern in Cairngorm.
  • FrontController [Reference] - The FrontController maps a CairngormEvent to a Command.
  • ICommand [Reference] - For a Command to function properly in Cairngorm, it needs to implement the ICommand interface. This interface requires that a command have a method named execute and that it accept the CairngormEvent that is mapped to it as an argument.

The Cairngorm Event Flow

The way that these classes interact is the Cairngorm Event Flow. Figure 2 illustrates this entire process. While this process seems lengthy, it follows a logical order.

Basic Cairngorm Event Flow

Figure 2 - Cairngorm Basic Event Flow

For example, assume that Figure 2 shows what happens when a user clicks a login button. It would follow the following steps:

  1. The user is viewing a component that has a login button.
  2. When the button is clicked, that component would dispatch an event named LoginEvent that extends CairngormEvent.
  3. The FrontController would receive the LoginEvent and execute the command that is mapped to that event. For this example, it will be named LoginCommand and will implement ICommand.
  4. The Command is executed and received the LoginEvent as an argument. The LoginCommand will change the workflowState value in the ModelLocator.
  5. The ModelLocator will have a predefined constant for the "Logged in View". The command will change workflowState to this value.
  6. Since the view is bound to workflowState, it will automatically update itself to the new view.

Once these items are understood, the next most important thing to understand about Cairngorm is: Everything Should Be Mapped to an Event. This is a drastic over-simplification, but it holds true in most situations. When a user clicks a login button - it should dispatch a CairngormEvent. When the user selects an option to change the view - it should dispatch a CairngormEvent. When a user submits a form to be stored on in a database - the form should dispatch a CairngormEvent. The dispatching of a CairngormEvent sets everything in motion.

Custom CairngormEvents

The class CairngormEvent can be used inside of your project, but in most situations you will create your own custom events that extend CairngormEvent (as stated previously, for an event to be included in the Cairngorm Event Flow it should extend CairngormEvent). Another reason to create custom events it to create custom properties of the event which contain data that you need to pass to the command. CairngormEvent has a property named data (of type Object) that can contain data, but it is ideal to have a strongly-typed property where you can place the data to pass.

For this example you will create an event that corresponds to the earlier example of a login page. This event will need to meet the following criteria:

  • Extend CairngormEvent
  • Have a property for the username
  • Have a property for the password

Code Example 1 illustrates this completed event. You can see that you will need to import both CairngormEvent and the basic Event class. Also, as with all events, you have to define the Event constant. In this instance, you can use LOGIN. The properties are defined below the constant - and they also are passed into the constructor. The only thing out of the ordinary is that you need to override the public method clone(). This is the the method that the event uses to make a copy of itself. This is key in the Cairngorm Event Flow. Also, for the function to implement ICommand this method will need to have a return type of Event (and not CairngormEvent).

Actionscript:
  1. package net.davidtucker.CairngormSample.events {
  2.    
  3.     import com.adobe.cairngorm.control.CairngormEvent;
  4.     import flash.events.Event;
  5.    
  6.     public class LoginEvent extends CairngormEvent {
  7.    
  8.         public static const LOGIN:String = "Login";
  9.        
  10.         public var username:String;
  11.         public var password:String;
  12.        
  13.         public function LoginEvent(submittedUsername:String,submittedPassword:String) {
  14.             username = submittedUsername;
  15.             password = submittedPassword;
  16.             super(LOGIN);         
  17.         }
  18.        
  19.         override public function clone():Event {
  20.             return new LoginEvent(username,password);
  21.         }
  22.    
  23.     }
  24. }

Code Example 1 - Custom Event

Commands

The Commands within a Cairngorm application actually "command" the application. Even in the next tutorial where you will be interacting with a server, the command still will do a majority of the work. In this example you will create a component that will receive the username and password from the LoginEvent, check the values against hard-coded values, and then change the workflowState on the ModelLocator if the values are correct. The following example performs these steps (but it doesn't have the hard-coded values included - that will be covered in the video).

The first thing to notice about the code below in Code Example 2 is that the LoginCommand implements ICommand. To accomplish this the ICommand class is also imported. In addition, you will notice the boilerplate code that you have used in the past to bring in the ModelLocator. To properly implement ICommand, the method execute() is also created. It received an event of type CairngormEvent (it has to be CairngormEvent and not LoginEvent to properly implement ICommand). To properly use the event, you will need to cast this event to the type LoginEvent (the process of casting will be further explained in the video). The actual logic has been left out of this command, but you can see that the ModelLocator updates the view. Once the logic is implemented this line of code would probably be inside of an if statement.

Actionscript:
  1. package net.davidtucker.CairngormSample.commands {
  2.    
  3.     import com.adobe.cairngorm.commands.ICommand;
  4.     import com.adobe.cairngorm.control.CairngormEvent;
  5.     import net.davidtucker.CairngormSample.events.LoginEvent;
  6.     import net.davidtucker.CairngormSample.model.ViewModelLocator;
  7.        
  8.     public class LoginCommand implements ICommand {
  9.        
  10.         public var modelLocator:ViewModelLocator = ViewModelLocator.getInstance();
  11.        
  12.         public function LoginCommand() {
  13.         }
  14.        
  15.         public function execute(event:CairngormEvent):void {
  16.        
  17.             var loginEvent:LoginEvent = event as LoginEvent;
  18.            
  19.             // COMMAND LOGIC
  20.            
  21.             modelLocator.workflowState = ViewModelLocator.WELCOME_SCREEN;
  22.            
  23.         }
  24.     }
  25. }

Code Example 2 - Cairngorm Command

Front Controller

As stated earlier, the FrontController maps your CairngormEvents to specific commands. Without this, your events would never integrate into the Cairngorm flow. The class extends FrontController and has two methods: the constructor and the initialize method. The initialize method is where you will use the addCommand method to map your events to commands (as you can see with the LoginEvent and LoginCommand).

Actionscript:
  1. package net.davidtucker.CairngormSample.control {
  2.    
  3.     import com.adobe.cairngorm.control.FrontController;
  4.    
  5.     import net.davidtucker.CairngormSample.commands.*;
  6.     import net.davidtucker.CairngormSample.events.*;
  7.    
  8.     public class SampleController extends FrontController {
  9.    
  10.         public function SampleController() {
  11.             this.initialize();
  12.         }
  13.        
  14.         public function initialize():void {
  15.            
  16.             //ADD COMMANDS
  17.             this.addCommand(LoginEvent.LOGIN,LoginCommand);
  18.            
  19.         }
  20.    
  21.     }
  22. }

Code Example 3 - The Cairngorm FrontController

Simply creating a FrontController is not enough. Like any class it needs to be instantiated inside of your application. Code Example 4 illustrates how to instantiate your FrontController in the Main.mxml file of your application. You simply need to add the control directory as an XML Namespace and then include the FrontController tag in the file.

mxml:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  3.     xmlns:control="net.davidtucker.CairngormSample.control.*"
  4.     layout="absolute">
  5.    
  6.     <control:FrontController id="controller" />
  7.  
  8. </mx:Application>

Code Example 4 - Integrating a FrontController

Now that you have seen the basic elements of a Cairngorm project, you can actually build the working sample with the video. As always, the application code is included below.

Application Code
Download (7 Kb)

Looking Ahead

This is the basic Cairngorm flow. You may notice that this flow really does not include any "Services" yet. Server interaction will introduce a few additional steps to the flow (which will be covered in depth in the next tutorial).




76 Responses to “Getting Started with Cairngorm – Part 3”

  1. Oliver Merk says:

    Hi David,

    In code sample #1, I’d recommend putting the additional properties inside the “data” object which is defined in ICommand:execute() [http://www.davidtucker.net/docs/cairngorm/com/adobe/cairngorm/control/CairngormEvent.html#data]

    Also, it might be better practice to pass in a loginVO to the LoginEvent() constructor rather than individual properties. The idea being that the loginVO would get sent to the back-end service.

    Excellent articles. Looking forward to the next one!

  2. David Tucker says:

    It should go in a VO, but I didn’t want to dive into VO’s until the next tutorial (this tutorial ended up being a bit longer than originally intended). In the next tutorial, I will cover VO’s and the ServiceLocator.

  3. Erno says:

    Thanks again for great tutorial!

  4. Nx8220 says:

    Just perfect! Thanks

  5. Terry says:

    Excellent. Thanks a million for these tuts, very helpful! When is part 4 coming? :)

  6. David Tucker says:

    I estimate that Part 4 will be published this weekend. I wish I could have it done sooner, but I try to be sure they are as thorough and error free as possible.

  7. Adam Soltys says:

    These tutorials are fantastic David, they are helping me dig into Flex more than anything else I’ve been able to find out there so far, keep ‘em coming!

  8. Tony Zhang says:

    It is very helpful for me .Hope to see next one soon.Thanks.

  9. [...] basic Cairngorm Event Flow that is handled in Part 3 is essential to any Cairngorm application, but most applications interact with a server. The [...]

  10. Flex New Guy says:

    David,
    While I was waiting for part 3 I looked into PureMVC as well. Seems to be a lot of similar concepts between the two frameworks. PureMVC has a lot of talk around it right now – any experience or insight into how it compares to Cairngorm? Cairngorm is backed by Adobe, but PureMVC seems to be a little bit more straight forward and a little easier to grasp. Again, finding your tuturials the best material on Cairngorm yet.

  11. David Tucker says:

    @Flex New Guy – PureMVC is certainly getting a lot of buzz. I have briefly looked into it, and I am still evaluating it for enterprise-level solutions.

    I do have one note though – if you are a professional Flex developer, you need to know Cairngorm. It was the framework that Adobe supported, so many companies still rely on Cairngorm (and will continue to – even if “easier” frameworks come along).

  12. frank says:

    thank very much

  13. buzzLightyear says:

    This is completley irrelevant, but I really wish this was named something other than “Cairngorm”. What a lousy name. Not slick, doesn’t roll off the toungue, and just conjurs up a picture of something completely hopeless, much like a hurricane hitting the Gulf coast.

  14. Holly says:

    Thanks for taking the time to do these tutorials. Some things are finally starting to “click” regarding Cairngorm.

  15. Freddie Fisher says:

    Great tutorial… however as soon as I instantiate the controller in the program, either the way you do or with AS3, the application fails to build silently. very puzzling! I’m using latest SDK with FlashDevelop, same problem with Flex builder 3. The code is downloaded from this page. Please help me!

  16. Pankaj Tiwari says:

    Excellent tutorials !
    I read several articles to understant “Service to Worker” pattern,
    this article helped me a lot understand it!
    Thank’s again !!!

  17. [...] David Tucker – Web Development Goodness » Blog Archive » Getting Started with Cairngorm – Part 3 Looking for some examples of how people break up flex directory structure (tags: cairngorm flex) [...]

  18. onur gunduz says:

    great tut thanks

  19. Shannon says:

    Great tutorial, thank you so much.

    I was wondering how to structure my cairngorm directories for things I resuse in multiple applications, such as the login/logout screens.

    Thanks,
    Shannon

  20. lhz says:

    very thanks

  21. jack says:

    public class SampleController extends FrontController {

    public function SampleController() {
    this.initialize();
    }

    public function initialize():void {

    //ADD COMMANDS
    this.addCommand(LoginEvent.LOGIN,LoginCommand);

    }

    }
    }

    according to your codes of LoginEvent class,LoginEvent.LOGIN==”Login” which is a String value.
    so we can see that code “this.addCommand(LoginEvent.LOGIN,LoginCommand)” just map the LoginCommand to a String value,rather than an event.

    it confused me.

  22. [...] Tucker :: Getting Started With Cairngorm :: Part 1 :: Part 2 :: Part 3 :: Part 4 :: Part [...]

  23. Shainy says:

    Excellent.:):)

  24. TsengYuen says:

    Hello,I come China.

    Very Great tutorial.Thanks!

    I wanna to learn more and more,so,please updata more and more tutorials.

    : ) I’m glad come here.

  25. Arnold Aprieto says:

    This tutorial will help millions of developers who are into flex. Thank you so much for sharing this information. Cairngorm may be a bit hard to comprehend by just reading a book or information, the additional video tutorial really helped a lot. Now I’m beginning to see and understand the Cairngorm way.

  26. JD says:

    Thanks so much! I just bought the Air 1.5 Cookbook, knowing the explanations would be understandable and complete. Just converted an application to Cairngorm and it may be my imagination but performance seems to have nearly doubled.

    Thanks again

  27. svp says:

    it’s really useful

  28. pride_conan says:

    Super tutorials. Thanks

  29. SM says:

    Thanks for your hard work. Excellent and clear tutorials.

  30. Maggie says:

    Thanks for all of your tutorials! I’m not sure where the best place to post this is, but I am wondering what the best way to handle multiple workflow states in Cairngorm. For example, the modelLocator dictates the workflowstate of my main views (8 of them). Within each view, there are views (e.g. each module will need to link to sub-modules. I initially got things working by creating another set of public static const(s) in the modelLocator, but when populating and XML tree and then attempting to link to the main modules and sub-modules, the workflow state numbers started to overlap, and the main workflow state would always trump the others. It almost seems like there needs to be separate modelLocators for each sub-module, but it seems like that is a no-no. What are your thoughts as the best way to handle it. To get an idea, in my modelLocator I have something like this:

    public static const LOGIN_SCREEN:uint = 0;
    public static const WELCOME_SCREEN:uint = 1;
    public static const ADMIN_SCREEN:uint = 2;public static const ORDER_SCREEN:uint = 3;

    public static const ORDERVIEW_DASHBOARD:uint = 0;
    public static const ORDERVIEW_CHECKOUT:uint = 1;

    (so, a separate viewstack has been instantiated for the submodule using the “ORDERVIEW_..” constants. Hopefully there is already a better way to handle this. Any advice?

  31. Maggie says:

    Hi again, sorry I think figured it out – I just created different variables for the workflowstates (e.g. in the model locator set a mainflowState and an orderworkflowState) and that helped me manage the multiple nested view stacks.

  32. firemonk says:

    very nice tutorial. I have seen many articles but none of them come any close to this.

    Great

    thank you

  33. Lenne says:

    Wow, thank you for these excellent quality video tutorials!

  34. newton says:

    I really appreciate your tutorial. Looking at different comprehensions I found yours to be simple enough to understand. Thanks.

  35. David Tucker says:

    @Newton – Thanks! I am glad that it was useful.

  36. [...] Now that you have seen the basic elements of a Cairngorm project, you can actually build the working sample with the video. As always, the application code is included below. [...]

  37. [...] basic Cairngorm Event Flow that is handled in Part 3 is essential to any Cairngorm application, but most applications interact with a server. The [...]

  38. Venkata says:

    Hi David,

    The videos are very useful & gave me a clear idea on MVC in Flex.

    I have a doubt on “IModelLocator” interface, i tried not to implement any “IModelLocator” in program but results the same .I don’t see any difference(probably i might miss somethings) . Could you please give me a idea on the services provided with the same .

    Thanks,
    Kiran

  39. daslicht says:

    Thank you very much David,
    this is the first Cairngorm Tutorial which opens my eyes.
    Go ahead :D
    <3
    dl

  40. Nizar says:

    Goooooooooooood job David
    I appreciate your work on this.

    Looking forward to the next one!

  41. Joe says:

    Quick question. At the end of the tutotial, you map the click event for the login button like so:

    click=”{login(event)}”

    Do the curly braces serve any specific purpose when used in conjunction with in-line AS3 coding?

  42. SM says:

    I’ve been trying to work with Cairngorm for a while…
    This really clears things up! Thanks for all your hard work.

  43. Greg Franklin says:

    Hi David, I am following along in your tutorial videos, and I got stuck on tutorial 3. Example 1, LoginEvent.as is giving me an error in Eclipse Flex Builder: “1046:Type was not found or was not a compile-time constant: Event”. Which is strange because I certainly has import flash.events.Event;
    in the code there. Is there something wrong with my Flex Builder class path configuration or something?

    Thanks.

  44. SM says:

    So, from reading this, it seems we are to only standardize the data objects coming FROM Flex to ColdFusion.

    Result data returned from CF is sent to the command where the result ‘action’ takes place in the responder.

    I.E. – My understanding is that the data returned from CF (Database) is used by the command and does not have a VO associated with it.. right?

  45. [...] recordings). I have been following this excellent series of tutorials by David Tucker. On part 3, David goes through the complete architecture. I have been trying to wrap my head around the [...]

  46. Nathan says:

    Hi David !

    This is an amazing stuff on Caringorm/.. Thanks a lot man..

    Need one more thing, how to manage different components in a single view..

    Please help me out..