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. diamondtearz says:

    This is by far the clearest Cairngorm walkthrough/tutorial that I have ever read/worked through. I really appreciate that you took the time to explain why certain things are done the way they are and address some alternative approaches and their flaws.

  2. Clyde says:

    Thank You mr.Tucker, your tutorials are amazing.

  3. [...] Artigo sobre Cairngorm parte 3 e o Vídeo Cairngorm Part 3 [...]

  4. Jatin says:

    Nice and simple article.
    I had encountered cairngorm in my last project but it is hard to unwire its element .this was really easy and simply explain.
    Thanks

    Jatin

  5. Rohit Marathe says:

    Thanks a lot David for this amazing series of tutorials on Cairngorm.
    It has made life of new learner very easy.
    Following link is also good for very basic knowledge with some animation.
    http://www.alamgirdesigns.com/2009/01/flex-animated-cairngorm-tutorial/

  6. Sergei says:

    Thank you for the very good tutorials although a few questions remains:

    1) Why the LoginEvent has to be cloned?

    2) Why the event parameter in the execute method should be casted as a LoginEvent, if the LoginEvent was already ‘properly’ mapped by the FrontController.
    Regards,
    Sergei.

  7. Hemant says:

    Its very good tutorial. you have explain each and everything very clearly. Thanks a lot..

  8. it is really an excellent piece of training. Now i can have the actual view of this architecture. proceeding to part 4. thanks David.

  9. Sergei says:

    It seems to me that in order to be consistent with the idea of loosely couple application development the WelcomeScreen.mxml view

    should be replaced as follows

    It is of course required to add a new Event and a modification of the controller.

    Regards

  10. Sergei says:

    the code was removed..

    import net.davidtucker.CairngormSample.events.LogoutEvent;
    private var modelLocator:ViewModelLocator = ViewModelLocator.getInstance();
    private function logout(e:MouseEvent):void
    {
    var logoutEvent:LogoutEvent = new LogoutEvent();
    logoutEvent.dispatch();
    }

    and the button click executes the above method

  11. Rkm says:

    Great Job. Thanks.

  12. ucef says:

    hello
    please i want any solution which can help me!!!

    i ve a probleme in LoginEvent after debug
    and when it pass to super(LOGIN);
    there is the follow message :
    source not found edit source lookup path…

  13. [...] is the original post: Getting Started with Cairngorm – Part 3 Categories: Adobe, Cairngorm, Cairngorm Architecture, flex Tags: Cairngorm, controller, Custom, [...]

  14. Adithya says:

    Great Job! Very clear and precise. Many Thanks.

  15. Nagrjuna says:

    Excellent…..
    Everyone can understand easily……
    Great job…

  16. Eric says:

    Question:
    If the modelLocator variable in the ViewModelLocator class is static, why don’t we just change it to be public so that we don’t have to initialize a boilerplate modelLocator in every class that uses it. Would this compromise security because then anyone could access it and change it? If so, doesn’t making each new variable modelLocator public for each class that uses it already compromise security?

  17. Amit Kumar Jain says:

    Thanks for such a great tutorial. Very easy to understand

    Thanks again for the great work :)

  18. Monica says:

    Hi, I really have no idea where I can post my problem, but I learned what I know (atm not so good jet but getting there) here. I am getting a problem where on the one place, I login to the system, then I logout. But when I want to login again it runs through my loginCommand (did the delegate run as well) but on the close bracket it just stops and doesn’t go anywhere. when I debug and step through I get “Source not found” on “com.adobe.cairngorm.control::FrontController/executeCommand” I have been stuck on this for some time now, it happens in other places in my program as well. Any ideas

  19. Apurv Khadamkar says:

    simply awesome…but i do not understand why to clone the Login Event? could anybody explain this?

  20. Gaurav says:

    Thanks Devid a great tutorial

  21. Really great tutorial! For me not being the native speaker in English, it was very nice to be able to understand all of the lectures. Speed was not high so that I fail to understand and not slow to get you board. The setup is crystal-clear, coding is so informative. I wish I could tell more, but one can’t effectively describe the beauty by words :D

  22. Sreedhar Uttakalla says:

    Hi David !

    Excellent tutorial, great job

    Thanks
    Sreedhar Uttakalla

  23. Thiago Sacramento says:

    muito bom mesmo….

  24. Megha says:

    Hi David,

    Thanks for such good tutorial on cairngorm.
    Before reading this tutorial cairngorm was very hard to me.

  25. Kunal Bhatia says:

    Thank You Mr.Tucker, your tutorials are amazing.

    ( :

  26. Deepanshu says:

    Wow ,Nice Tutorial mr.tucker
    Really Helpfull to understand and implement.