CairngormLogin ColdFusion Example

Author: Renaun Erickson – 2007.07.30

Technology Used as of 2007.07.30:
Mac OS X (10.4.10 when article was created)
ColdFusion 8
Flex 3
Cairngorm 2.2.1 Beta
XAMPP for OS X
CairngormLogin Example Original Post
Neil Webb to Cairngorm 2.2. Check out his series of articles explaining Cairngorm using the Login example.
CairngormLogin with ColdFusion backend

Purpose:
To demonstrate the basics of Cairngorm in a working application using Flex and ColdFusion.

Setup:

    XAMPP

  1. Download latest XAMPP for OS X
  2. Follow instructions on XAMPP’s site: Installation, Start, Test
    ColdFusion 8

  1. You need Admin rights to install ColdFusion 8 on Mac OS X.
  2. Download the Developer Edition of the ColdFusion 8 from Adobe.com
  3. Unzip the downloaded Mac OS X version of the ColdFusion 8
  4. Open a Terminal. Type “sudo open ” in the terminal. Then navigate to the “ColdFusion 8 Install.app” that you unzipped. Drag it over to the Terminal app, it will paste the path for you (should look something like “sudo open /Users/renaun/Desktop/downloads/ColdFusion\ 8\ Installer.app/”. Click enter.
  5. Now we are in the ColdFusion Wizard, here are what I selected as the installation options
    1. Clicked Ok
    2. Clicked Next
    3. Clicked “I accept….” and then Next
    4. Checked the Developer Edition and then clicked Next
    5. Select the “Server Configuration” option , then click Next
    6. I had no other installs, so left it checked No, and clicked Next
    7. I did not want the documentation, startup scripts, or Adobe LiveCycle Data Services ES. I unchecked all 3 and then clicked Next
    8. I left the default install directory “/Applications/ColdFusion8″, and clicked Next
    9. I did not need to update from earlier versions of ColdFusion, so I left it No and clicked Next
    10. I left “Configure web server connected for ColdFusion” selected and clicked on the Add button. Use the values below to fill out the form, then click OK
    11. Web Server: Apache
    12. Config. Dir: /Applications/xampp/etc
    13. Dir and file name of server binary: /Applications/xampp/xamppfiles/bin/httpd
    14. Dir and file name of server control script: /Applications/xampp/xamppfiles/bin/apachectl
    15. Click Next
    16. I put my CFIDE in the default Mac web sites folder, which I changed the “DocumentRoot” value in the /Applications/xampp/etc/httpd.conf file of xampp also. So select your default web server DocumentRoot. Either:
      /Applications/xampp/xamppfiles/htdocs
      /Users/renaun/Sites/
      Click Next
    17. Enter a password for the CFIDE administration login and click Next
    18. Enabled RDS and give a password if you want. I did not, click Next
    19. Provide your Mac OS X user’s password and click Next
    20. Click Install and wait for it to install
    21. Click Ok, and it will open the CFIDE administration login wizard
    22. Log in with your password setup eariler in the wizard
  6. To Start/Stop ColdFusion manual open a Terminal app and type in Either:
    sudo /Applications/ColdFuions8/bin/coldfusion start
    - or -
    sudo /Applications/ColdFusion8/bin/coldfusion stop
    Example Code Source Files “CairngormLoginColdFusion.zip”

  1. Download source code zip file and unzip it and put the two Folders “com” and “CairngormLoginColdFusion” in your web DocumentRoot.

    Either:
    /Applications/xampp/xamppfiles/htdocs
    /Users/renaun/Sites/
    Cairngorm 2.2.1 Beta Source

  1. Download the Cairngorm 2.2.1 Beta source and unzip it. Make note of the path.
    Flex Builder 3 – Standalone

  1. Download latest Flex Builder 3 beta off labs.adobe.com
  2. Install the standalone Flex Builder 3, click Next to everything and install it in the default location.

Code Project Setup:
Now it’s time to start Flex Builder 3 and get the project’s up and running.

    Setting up the Cairngorm Source project

  1. In Flex Builder, in the Navigator view, right click and select “Import…” context menu item.
  2. Now select General->Existing Projects into Workspace and then click Next.
  3. Click the top right “Browse…” button and navigate to the path you unzipped the Cairngorm source code to. For me this was /Users/renaun/Desktop/downloads/Cairngorm/. Click Ok
  4. You should see a project called “Cairngorm” in the Projects list. Make sure its checked and click the Finish button
    Setting up the CairngormAccountManagement project

  1. In Flex Builder, in the Navigator view, right click and select “Import…” context menu item.
  2. Now select General->Existing Projects into Workspace and then click Next.
  3. Click the top right “Browse…” button and navigate to the web DocumentRoot where you unzipped the example source code. For me this was /Users/renaun/Sites/CairngormAccountManagement/. Click Ok
  4. You should see a project called “CairngormAccountManagement” in the Projects list. Make sure its checked and click the Finish button
  5. Click on the CairngormAccountManagement project in the Navigator pain, right click on select the Properties context menu item
  6. Select the Flex Build Path page, and the Source Path tab. Click the “/Users/renaun/Sites/com/” folder and click the Edit button
  7. Navigate to the “com” folder of your respective web’s DocumentRoot
  8. Change and click Ok

The Walkthrough of How and the Whys
The following part of the tutorial will walk you through the basics of Cairngorm and how to hook up ColdFusion as the backend of the CairngormLogin example. You can read more about the CairngormLogin example on Alex Uhlmann’s blog and Neil Webb’s posts.

First, we need to cover some of the basic Cairngorm terminology. One of the best ways to describe the Cairngorm framework is with the Cairngorm Diagram Explorer (http://cairngormdocs.org). Its split up into the Model View Controller (MVC) model with parts like ModelLocator, FrontController, ServiceLocator, BusinessDelegates, Commands, and Events.

In the process of explaining some of these Cairngorm concepts, we’ll take the original CairngormLogin example and add a working ColdFusion 8 backend (using MySQL from XAMPP), change LoginVO into AccountVO, add a type to the AccountVO, and create a AddAccount view to add more accounts.

A good place to start is in the CairngormLogin.mxml file. Go ahead and open up the file and take a look at the bottom half, the code after </mx:Script>. In this section of the code the Services, Controller, and main Views are defined. Lets dive into the Services class. Double Click on the “Services” text of the line of code “<services:Services id=”loginServices”/>, and then click F3. This will take us right into the /com/adobe/cairngorm/samples/login/Services.mxml file. The ServicesLocator class of Cairngorm provides a one stop shop for all services of the application. This is nice and handy place to make all your service declarations, be it RemoteObject, WebService, or HTTPService. The com.adobe.cairngorm.samples.login.LoginService.cfc component expose a “login” method. To make this service available lets add it to Services.mxml, here is the code:

<mx:RemoteObject
 id="loginService"
 source="com.adobe.cairngorm.samples.login.LoginService"
 destination="ColdFusion"
 showBusyCursor="true">
</mx:RemoteObject>

Our loginService now is defined to look to the com.adobe.cairngorm.samples.login.LoginService.cfc for any method calls on it. Lets go to the ColdFusion for a second. Open up the LoginService.cfc and take a look at the “login” method. It takes an argument of AccountVO, which we’ll define both on the ColdFusion and ActionScript side, checks the username and password, and then returns an AccountVO if a valid account. You can find the ColdFusion AccountVO at com.adobe.cairngorm.samples.login.vo.AccountVO.cfc. It is a basic CFC with some properties and init script.

Lets take a step back and go back to the CairngormLogin.mxml page. With a valid Services defined in Services.mxml we are ready to talk about how the actual user interaction goes from the screen to our Services CFC and back into our application. The next important step in the Cairngorm arichecture is the Controller. In our case, the com.adobe.cairngorm.samples.login.LoginControl class. Double click on “LoginControl” in the line of code “ and press F3. A FrontController is the brains of the operation. It knows what requests made by the user interaction on the View side of things correlate to the Commands/Business Delegates on the application business logic side. This is done with a basic lookup mechanism which the FrontController defines the key as the Event type and the value as the Command class. Under the hood of the FrontController implementation is the magic where it sets up event listeners on the specific events to be ready to fire of any Commands.

This also makes it easy to define business logic regardless of the applications View or view state. Any place in the application you dispatch a event with the type “LoginControl.EVENT_LOGIN” and it calls the LoginCommand. The Commands go and do their stuff and then come back with some result. All the while don’t have to think about creating the Command or worrying about handling its result in the same place as where you made the call (this is where the ModelLocator comes in which we’ll talk about more in a bit).

Ok, enough rambling, lets look at the code. We know that LoginControl defines a lookup for “LoginControl.EVENT_LOGIN” to a Command called LoginCommand. The EVENT_LOGIN event is fired on the Login button in LoginPanel.mxml.

...
public function loginUser() : void
{
    var accountVO : AccountVO = new AccountVO();
    accountVO.username = username.text;
    accountVO.password = password.text;
   
    var event : LoginEvent = new LoginEvent( accountVO );
    event.dispatch();
}
...
<mx:Button label="Login" enabled="{ !login.isPending }" click="loginUser()"/>

You see that upon clicking on the Login button it fires off a local method called “loginUser()”. In the method it creates an AccountVO, passes that into a new LoginEvent, and then dispatches the event. No LoginCommand in site. Pay attention to the “!login.isPending”, the login property is set back on the CairngormLogin.mxml page:

...
<view:LoginPanel id="login" login="{ model.login }"/>
...

Now we have are torn between talking about the “model.login” (ModelLocator) and continuing following the process of the Login event. The model will have to wait again. We know that the FrontController will create and fire off (calls the execute method) on the LoginCommand behind the scenes because we dispatch a LoginEvent (which defaults to LoginEvent.EVENT_LOGIN type). Lets take a look at the important parts of the LoginCommand class:

[javascript]

private var model : ModelLocator = ModelLocator.getInstance();

public function execute( event : CairngormEvent ) : void
{
model.login.isPending = true;

var delegate : LoginDelegate = new LoginDelegate( this );
var loginEvent : LoginEvent = LoginEvent( event );
delegate.login( loginEvent.accountVO );
}

public function result( event : Object ) : void
{
var accountVO:AccountVO = AccountVO( event.result );
if (accountVO.accountid > 0)
{
model.login.loginDate = new Date();
model.login.accountVO = accountVO;
model.login.isPending = false;

model.workflowState = ModelLocator.VIEWING_LOGGED_IN_SCREEN;
}
else
{
model.login.statusMessage = “Invalid Username or Password!”;
model.login.isPending = false;
}
}

[/javascript]

The execute method contains a new class, the LoginDelegate. The BusinessDelegates create a pseudo proxy for the actual method calls on the Service classes. They also define a pattern to get the results (result/fault methods through a IResponder). You’ll see the “delegate.login(loginEvent.accountVO)” makes a call on the delegate that in turns makes the call on the “loginService” from our Services.mxml.

The call is made and the result or fault method is called by the responder. You’ll see a “event.result” property inside the result(event:Object) method. We defined the LoginService.cfc’s login method to return an AccountVO, therefore we can cast the event.result as an AccountVO and do our check on the accountid.

The use of RemoteObject service provides us with resquests/responses in the Action Message Format (AMF). The AMF format allows for type classes. We created the AccountVO.cfc, it was just a plain CFC. To correlate this with an ActionScript class that the AMF serialization can convert to we define the AS class like so:

[javascript]
package com.adobe.cairngorm.samples.login.vo
{
import com.adobe.cairngorm.vo.IValueObject;

[RemoteClass(alias="com.adobe.cairngorm.samples.login.vo.AccountVO")]

[Bindable]
public class AccountVO implements IValueObject
{
public var accountid : Number;
public var username : String;
public var password : String;
public var type : String;
}

}
[/javascript]

The special code that lets AMF know how to convert the class is [RemoteClass(alias="com.adobe.cairngorm.samples.login.vo.AccountVO")]. If you where to use ServiceCapture or Charles HTTP you would see the type request and response as AccountVO objects.

What takes us back to the View state is the code in the LoginCommand that changes the model, “model.login.isPending = false;” and “model.workflowState = ModelLocator.VIEWING_LOGGED_IN_SCREEN;”. The first changes the enabled state of the LoginPanel.mxml’s Login button back to be enabled. The 2nd code snippet is where the magic of the View change happens. This also is one of the best illustrations of the ModelLocator pattern and its power when couple with ActionScript’s binding capability.

First lets talk about the model in general. The ModelLocator pattern provies a single place to storage data for the application. It implements a singleton pattern so only one copy of the data is present. It is basically a holding place for a bunch of global data. So the same pitfalls of global variables do apply here, but when used in connection with Commands you can structure model manipulation to maintainable business logic chunks.

Lets look at the model.workflowState property. Here it is getting changed on a LoginCommand. But what does it do, well back to the CairngormLogin.mxml file. The ViewStack (id=”appView”) references it in the binding of selectedChild to a function getView(model.workflowState). Inside getView() we see that the model.workflowState is check and defines which child the ViewStack displays. Interesting, so changing one value on the model in an LoginCommand class fired off in the LoginPanel view caused the ViewStack to change its view.

Now with some changes to AccountVO, I’ll leave it up to you to check out the other changes in MainPanel.mxml and the other Events and Commands that have been added to the CairngormLogin project.