What is Cairngorm?
The Cairngorm Microarchitecture is a lightweight yet prescriptive framework for rich Internet application (RIA) development.
Cairngorm is an implementation of design patterns that the consultants at Adobe Consulting have successfully taken from enterprise software development (with technologies including J2EE and .NET) and applied rich Internet application development using Adobe Flex.
|Governance||Learn how the Cairngorm project is governed|
|Roles||Understand the various roles related to the Cairngorm project|
|History||Get a quick time line of how Cairngorm came to be where it is today|
Cairngorm can be downloaded from here.
Cairngorm is available for both Flex 1.5 and Flex 2/3. All future efforts will be focused on the version for Flex 3 and all references to Cairngorm in this article refer to Cairngorm for Flex 2/3, unless otherwise stated.
At the time of the release of Flex 2, portions of the-then-named Flex Data Services were moved into LiveCycle Data Services, a licensable product. So as to ensure that Cairngorm could be used without the need for LiveCycle Data Services (for example, using BlazeDS), Cairngorm was packaged into two SWCs, once containing the core Cairngorm code, and one containing the code that had dependencies on classes in LiveCycle Data Services. This latter SWC is named Cairngorm Enterprise and is only needed when using the classes that ship with LiveCycle Data Services (Producer, Consumer and DataService classes).
Things have changed further with the release of Flex 3, and although the current package structure supports the latest release of Flex, Cairngorm will be changed to better reflect these changes in a future release.
Target Applications for Cairngorm
The Cairngorm microarchitecture is intended as a framework for Enterprise RIA developers.
First and foremost, this assumes that developers are likely to be delivering their applications on the Adobe Flex platform. As an ActionScript 2 and ActionsScipt 3 technical architecture, Cairngorm has been used, and can continue to be used, for the rapid development of applications built with Flash MX and Flash Remoting. However, the implementation of the design patterns (the patterns that have been selected for the microarchitecture) and the future roadmap for Cairngorm development are firmly aligned with the feature set – advertised and anticipated – of the Adobe Flex platform, and the emerging ecosystem of tools (such as Apollo) around the Flex platform.
If you are writing a very simple application (such as a prototype application) or an application with only a single view, then you might consider a “Model 1″ solution that doesn’t strive for the same separation of model, view, and control that Cairngorm advocates.
The benefits of the Cairngorm architecture are realized when developing complex RIA applications with multiple use-cases and views, with a team of developers, and with a multi-disciplinary development team that includes designers as well as creative and technical developers.
Ok, so I’m not going to try and teach the Cairngorm micro-architecture for Flex here. The kids at Adobe did a fine job of that.
Cairngorm follows the principle of separating the view and business logic which is known as the Model-View-Controller pattern (MVC). The following list shows the different elements that form the framework.
1. View: Contains UI controls for user interaction and displays the state of the models data. Views dispatch events handled by the controller.
2. Model Locator: It acts as a centralized repository for all data needed in the application. It manages the view an is declared as [Bindable] to use all variables for data binding in the view. It must be implemented as a singleton which implements the Cairngorm IModelLocator. All data managed in the model should only be updated through a command or a responder object.
3. Value Object (VO): A value object is a class that only has properties to store values. It contains no methods or logic and acts as a pure data container. Value objects must implement the Cairngorm ValueObject interface. If they should be mapped to a corresponding server-side class it must declare the [RemoteClass (alias=”)] metatag. By doing so, Flex automatically converts an server-side object returned through remoting or data service interaction to its corresponding ActionScript object.
4. Event: In Cairngorm everything should be mapped to an event. Whenever the user interacts with the view or an action occurs an event must be dispatched. Custom events extend the CairngormEvent class an have a special property to contain the data that comes with it.
5. Command: Commands actually do the majority of an applications work. They recieve the event and its data, execute the logic an can change the workflow state of the model and view. Each command must implement the Cairngorm ICommand interface and its execute function. The revcieved event is a generic CairngormEvent and must be casted to the appropriate custom event first. The complete frontend-logic of the RIA is encapsulated within the commands.
6. Front Controller: It extends the Cairngorm FrontController class and maps the dispatched events to its corresponding commands. Therefore it has two methods: the constructor and an initialize method which will map an event to an command via the addCommand method. The controller is instantiated directly in the main.mxml via a component tag. You simply need to add the directory your class is in as an XML Namespace and then include the tag in the file.
7. Service Locator: Implemented as a singleton, it contains references to all services an application will use. Like the Front Controller, it is placed within the main.mxml via a tag. Possible services to be used are RemoteObjects, HTTPServices, WebServices or custom services.
8. Business Delegate: Business Delegates form an abstraction layer between the server-side services and the main frontend application. The locate the required service in the Service Locator, call the given method on it and route the response back to a responder object. Unlike the other elemente in the Cairngorm architecture, it does not extend a class or implement an interface, but it need to follow some guidelines: it must have at least two properties, one named reference to the ServiceLocator and one reference to a responder, both set in the constructor. And it must have implemented one method for each server-side method to be called. The delegate is created within a command object. It should only pass strongly typed value objects to a responder. If it does not recieve an appropriate object, it must create one before passing it.
9. Responder: Responders implement the mx.rpc.IResponder interface. A responder recieves the result of a service call and implements frontend-logic like a command. It directly may set values of the model and should only deal with strongly typed value objects.
10. Service: The Service is formed by an application tier, build with some server-side technology like J2EE or PHP. It Accepts the service requests from the RIA and responds back data. With a remoting technology like BlazeDS it is even possible to pass back value objects witch are transformed to their corresponding ActionScript objects in the application, so it can interact with them as if they are created by script.
Cairngorm consist of the following interface, classes and function
CairngormEvent, FrontControler, ICommand, IResponder, IModelLocator, <cairgorm:SserviceLocator/> , IValueObject,
Override public function clone():Event //CairngormEvent
execute(event:CairngormEvent)// ICommand function
result(data:Object):void // IResponder
<cairngorm:ServiceLocator />// register a RemoteObject
token.addResponder(responder); //Register a responder aysnctoken which sends a request to service for updating or getting data.
MessagerModelLocator.getInstance().messenger //update the info in result and fault functions which isimplements Icommand, IResponder
Public static function get instance() selfclass if(_instance==null) _instance=new serlfclass() return _instance//IModelLoactor
What I am showing here is, a very simple implementation of Cairngorm. Even though I’d seriously recommend anyone starting out to look at the Cairngorm Store first, I thought I’d share my experience implementing a tiny Cairngorm solution. The solution here is essentially paraphrasing the Cairngorm Store source.
Note: it is set to run from http://localhost/TestCairngorm (you’ll need to setup this Virtual Directory to test it locally)
The project’s goal is to show the contents of an XML file, which will be deployed alongside the application.
It illustrates the steps needed to get your project off the ground in Cairngorm:
- Write a bindable model that extends from ModelLocator. Remember: the Model shouldn’t know anything about either the View or the Controller.
- Include code to the Singleton of that model in your main application
- Create your value objects (this was not strictly required in the above project, but added to highlight the correct structure).
- Write a services file that extends the ServiceLocator and contains all the services you want to access (HTTP/Web/Remote).
- Add the services to your main application.
- Write a delegate for each type of value object you have. This is optional but seems best-practise. The delegate will call the appropriate service via the service locator for each method it provides. It will ensure the responder (the command that calls the delegate) receives the response.
- Write a command for each of the various commands you have within your application. These should execute() the call to load your remote data via the delegate and handle the reception of data in result() (and likely modify your model)
- Write an event that corresponds to each command along with any data that will need to accompany the event (user data or what-have-you). Doesn’t have to be one event per command – you can combine events together in one class with different types.
- Write a controller (extending from FrontController) that adds all the commands to this Singleton when instanced (tying the events and the commands together)
- Add the controller to the main application.
- Start creating your view. Ensure that you bind your view items to your model elements, so that when the model updates, so will your view. Try not to reference your model in your view via the Singleton class name but rather pass the appropriate model data in from the main application. (This helps improve the reusability of your view, decoupling it from the model).
- Use the CairngormEventDispatcher to dispatch your events in the view as you see fit. This will then call the commands via the controller, which call the appropriate service, update the model if required, and will update your view.
A collaboration of recognized design patterns, Cairngorm exemplifies and encourages best-practices for RIA development advocated by Adobe Consulting, encourages best-practice leverage of the underlying Flex framework, while making it easier for medium to large teams of software engineers deliver medium to large scale, mission-critical Rich Internet Applications.