Cairngorm 3


Prerequisities

Before you go on, it is vital that you get familiar with Adobe Cairngorm framework itself. That is a simple yet powerful Model-View-Controller based microarchitecture and a set of design patterns. All is to make your web application development process far easier and more organised.

Should you want to read further on Adobe Cairngorm for Flex:

Should you want to read further on Adobe Flex:

Intruduction

Separation of concerns is a very important issue in software development. As a project manager and a designer, it allows you to split the work between the programmers and divide the whole process in major cycles. One of many, you create a model which represents the business logic that application is to implement. Based on that one may develop a set of activities (commands) that modifies the model (eg. adds a new customer or authorizes an user). The logic layer has nothing to do with how the application communicates with the user. Moreover, those areas are usually covered by different software teams.

Well designed user interface should let not only initiate certain processes but also track the progress and respond to the result of their execution. For example, you may want to switch the screen after a succesful login or pop a window up on error. Most unfortunately, there is no good way to acomplish that in Cairngorm. All the walk-arounds I have seen required the logic layer (model and commands) to rely significantly on the view layer. This resulted in a constant need to modify the logic simultaniously with the development of the view components.

The current (and poor) solutions involve:

  • Passing the references to the view components (as a Cairngorm event property) to the logic layer in hope that the needed changes will be made there.
  • Use of ViewHelper / ViewLocator in the logic layer.
  • Cluttering model with some view devoted properties (like viewingState).
  • Making model dispatch special events to inform the view about certain results of the commands execution. Leads to creation of tons of classes and code difficult to manage.

If the mentioned problems sound familiar, you shall find Cairngorm 3 higly useful.

Tell me when you are done

The most basic feature lets you pass a reference to the function which is to be called after the execution of the backing command is completed. You may provide an optional parameter to the well known call, eg:

new UserEvent(UserEvent.LOGIN, username).dispatch(userLoginComplete);

In the complete handler you may eg. switch to the main screen.

Example (Counter.mxml):

Smart readers have probably noticed that the complete handlers take one argument. The data carries detailed information about the executed command. We will get to this later on.

Glance at CairngormResponder (new class)

It often happens that command does not complete instantly. This is the case eg. when you use Remote Procedure Calls – calling a Web Service requires waiting for response. For this kind of commands you should make them extend the CairngormResponder base class.

Object of CairngormResponder is expected to dispach COMPLETE event after it finishes.
However, everything you have to do is simply to call:

super.result(null);

after you are done. As the parameter you may pass an execution result (see the next section).

Example (Delayed.mxml):

Handling result / fault of command execution

Normal results and errors should be treated differently. Each command assummes that certain preconditions are fulfilled (eg. username is not empty). You may respond to the wrong exectutions by throwing a descriptive error in the main execute() method:

throw new Error("Username is empty");

The error is then catched by the Controller and passed back to the command fault handling function. This works regerdless whether your command is CairngormResponder or not (one shall be instantiated anyway for the complete handler argument). Alternatively you can call CairngormResponder fault method directly: super.fault(error);

Note that this is the only solution if you want to react to the error information returned by the server
(outside the execute() method).

The complete handler may behave basing on the completion status:

protected function completeHandler(responder:ICairngormResponder) {
if (responder.succeded) {
// do sth with responder.resultData
} else {
// do sth with responder.faultInfo
}
}

For the full list of ICairngormResponder interface properties please check the documentation at the end.

Example (Fault.mxml):

Centralisation of handlers

It would be unhandy if you had to provide the same function in dispatch() call for every place in code where you dispatch a certain event. That is why the new controller lets you listen for completion of any or given command execution. Hence, you can put all the error-respoding code in one place. What is more, the controller will inform you if the command execution did not complete instantly so you can eg. change the cursor to the hourglass.

However, you can still use the dispatch-specific handlers to take the view specific actions eg. close a popup window.

Example (Global.mxml):

Track of progress and ability to cancel execution

The noticable number of processes provide progress information. Amongst others, those are downloaders / uploaders / data renderers. It would be great to give the user clue of how much time currently executed commands may consume. If your command does provide such information, you may find it useful to make it extend the CairngormProgressResponder base class. Then you simply dispatch appropriate PROGRESS events.

Ability to cancel the execution is even more important. Should you want your command to be cancellable, it is enough to implement the ICairngormCancelResponder interface, so that you can code the routine details.

Example (Progress.mxml):

Delegate base class

The extension to Cairngorm comes together with unification of the inter-layer communication:

Delegate base class is simply a kind of responder which you can instantiate on command’s behalf.
For example in execute() method you write:

delegate = new AuthorizationDelegate(this);
delegate.LoginUser(username);

Storing a reference to the delegate in CairngormResponder property prevents the garbage collector from getting rid of unreferenced service before it manages to return a result. The issue holds for the asynchronus commands which should be referenced somehow during the execution time. You already know how easily it can be done with ASYNCHRONOUS controller’s event handler.

Library resources

The extension is fully backward-compatible with the original Cairngorm. So you can probably switch the library files with no consequences (but on your own risk ;)).

The resources below are based on the Cairngorm v2.2.1 code obtained from Cairngorm SVN repository at Adobe OpenSource.

I also provide a patch file (for the latest – 2.2.1 beta) version of Cairngorm:

Those are the spots where I have made changes. Asterix stands for modification and plus for addition.

  • + business/Delegate.as
  • * control/CairngormEvent.as (dispatch, completeHandlerFunction)
  • * control/FrontController.as (executeCommand, responderComplete, events)
  • + control/FrontControllerEvent.as
  • + responder/CairngormProgressResponder.as
  • + responder/CairngormResponder.as
  • + responder/ICairngormCancelResponder.as
  • + responder/ICairngormProgressResponder.as
  • + responder/ICairngormResponder.as

You may review the changes by the means of the source code browser.

~ by mjcprasad2000 on July 17, 2009.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: