You are on page 1of 52

Developing Flex RIAs with Cairngorm Microarchitecture – Part

1: Introducing Cairngorm

Table of Contents
1. Introduction
2. Clarifying the Definition of Frameworks
3. Applying Design Patterns
4. A Short History of Cairngorm
• Printable version
• Send feedback
• Get an e-mail update of new articles
• Take a survey

Comments
Created:
13 February 2006
User Level:
Intermediate

This six-part series presents an open-source architectural framework to Flex developers called
Cairngorm. In this series I explain the thought leadership behind Cairngorm, the design challenges that
Adobe feels Cairngorm addresses best, and the projects for which Cairngorm is an appropriate skeleton
for development.
Using the Cairngorm Store sample application, this series explains what Adobe Consulting thinks about
scoping, estimating, and delivering a Rich Internet Application (RIA) when basing it on Cairngorm
from the start. I also explain the various Cairngorm concepts and take a deep dive into the
implementation of the Cairngorm Store.
Finally, I demonstrate some of the principal benefits of delivering an RIA based on this established
microarchitecture by adding a new feature to the existing Cairngorm Store application from the point of
view of a Cairngorm developer. By this stage in the series, you see the benefits for yourself.
Cairngorm isn't the only way to build a Rich Internet Application, of course. However, Adobe
Consulting has helped numerous customers and partners succeed in delivering large-scale Flex RIAs by
building upon their preexisting Flex application development knowledge using the information
contained in this series.
This comprehensive introduction covers the full spectrum of Cairngorm, from understanding the
motivation and concepts of Cairngorm to architecting your own applications upon this established and
supported microarchitecture.
Instead of delving into code from the outset, Part 1 offers a context and background for understanding
the Cairngorm architecture. I discuss frameworks and clarify the difference between an application
framework and an architectural framework. I then explore design patterns and introduce the
microarchitecture concept. Finally, I give a brief background on the emergence of Cairngorm: its
history and where it is headed—its roadmap.
In Parts 2–6, you will develop a retail commerce application using both Flex and Cairngorm on the
client-side tier and a new or existing J2EE infrastructure on the server-side tier.

Requirements

Clarifying the Definition of Frameworks


In software development, the term framework is one of the most overloaded and overused terms within
and between development teams. When developers write large pieces of code that they consider
significant enough to consider leveraging on other projects, they tend to supplement the code with this
term. Thus there are many types of frameworks: persistence frameworks, transaction frameworks,
logging frameworks, aspect-oriented frameworks, animation frameworks, unit-testing frameworks, and
the like.
Before I delve into the discussion of the Cairngorm framework, it's important that I explain an
important distinction that the Adobe Consulting team shares with customers and partners about
frameworks—specifically the distinction between application frameworks and architectural
frameworks.

Application Frameworks
Flex is a tremendous example of an application framework. In fact, the forthcoming release of Flex 2.0
actually distinguishes the application framework piece—often called the "app model" within Adobe—
in its architecture. The Flex Framework 2.0 provides a rich collection of class libraries that provide
highly granular functionality that developers can use to create custom code. For instance, the Flex 2.0
Collections API provides application developers with all the base-level functionality needed to create
managed data collections. Application developers then compose these collections together into higher-
level objects that are relevant to their particular application. Furthermore, application frameworks such
as Flex typically expose application-level services such as history management, layout management,
cursor management, exception handling, internationalization, logging, and so forth.
When a framework provides highly granular class libraries that give a high degree of flexibility to
application developers, or when a framework provides application-level services that are useful across
multiple developer projects, I call it an "application framework."
Another excellent example of an application framework is the FAST framework that Adobe Consulting
has used with customers and partners with great success. The FAST framework, as John Bennett
explains in his article, Faster Development with the Flex Application Starter Toolkit (FAST), provides
application services for logging and tracing, and value-add class libraries that extend the Flex
Framework's own implementation of RPC data services in Flex 1.x.
Architectural Frameworks
Architectural frameworks are different beasts entirely. Typically the job of an architectural framework
is not to provide any additional services to application developers except an infrastructure around
which an application can hang—to provide the skeleton or internal structure of moving parts, around
which the flesh and muscle particular to a business domain can be layered.
In other words, an architectural framework provides a generic starting point for the technical
architecture of your application.

Applying Design Patterns


It is hard to talk about technical architecture without paying attention to an important movement in
software engineering called design patterns.
Without going into detail about software design patterns, let me just say that the expression "there is
nothing new under the sun" is never more true than in the discipline of software engineering.
Developers often find themselves addressing engineering problems that appear with regular
consistency in application development. Almost as consistent as their appearance is the repetition of
solutions for these problems. Wherever such recurrences occur, you can identify the solution as a
"pattern," indicated by facing the design challenge and finding the appropriate design solution.

The Lure of Design Patterns


Now a warning: When software engineers first encounter design patterns, the realization of a catalog of
solutions to their engineering problems can be a powerful one. Often developers recognize a subset of
problems they have encountered and then seek to understand other design patterns and where they
might apply them. However, the old adage "when all you have is a hammer, everything looks like a
nail" can apply here. You can often find "pattern overload" in an application, where developers abdicate
responsibility for classes and collaborations and, instead, shoehorn everything into a Factory,
Flyweight, Observer, or Decorator.
Used appropriately, however, design patterns can be a powerful tool in a developer's toolbox. Design
patterns not only offer common solutions to problems, but the way developers apply them to an
application indicates the intention of the implementation. For instance, whenever you see a Singleton in
a code base, you understand that this is a class for which there should be only one instance. Likewise,
whenever you come across a Factory, you recognize that there are a number of different objects that a
manufacturing class can construct.
Rising through the technical architecture—from the ground-zero of detailed implementation towards
the helicopter view of high-level system design—you can begin to appreciate the design in other,
recurring ways. Like the Mandelbrot, you begin to recognize higher order structure as your lower level
structure collaborates. Thus design patterns begin to coalesce in repeatable ways, offering higher level
solutions to higher level design problems.

Microarchitecture as a Composition of Design Patterns


Although a design pattern might have offered a specific solution to a specific problem (in this case,
using the Singleton pattern for the problem of ensuring that only one instance of a class ever exists),
when a collection of patterns regularly collaborate with one other, their assembly is for the greater good
of a greater aim: "How do I intercept user gestures and ensure that a worker class assumes
responsibility?" or "How do I centralize the business logic that might be used in more than one context
on the client, even though it is actually implemented as a collection of service calls to a number of
different types of services on a collection of servers?"
When you start to assemble collections of design patterns into these higher order but nonetheless highly
generic systems, you communicate these as "microarchitectures."
Let's take this high-level discussion of application frameworks, architectural frameworks, design
patterns, and microarchitectures and put it into context. When Adobe Consulting speaks about the
Cairngorm framework, we are speaking about an architectural framework—a starting point for
technical architecture that is generic enough to apply in most cases to medium-to-complex Flex RIAs.
Furthermore, when we speak about the Cairngorm framework, we do not mean some monolithic
architecture that limits your freedom as a developer to solve problems. Rather, when we advocate the
Cairngorm framework, we mean the following:
• A lightweight framework that offers a little prescription for some of the challenges consistent
with the Flex RIAs we have encountered
• Using a small number of relevant design patterns, where the moving whole is ever so slightly
greater than the sum of its static parts
• A microarchitecture for RIA development—a starting point for your technical architecture that
solves the problems as they have been solved successfully before
If we can see further, it is because we are standing on the shoulders of giants.

A Short History of Cairngorm


iteration::two, a software consultancy that Alistair McLeod and I cofounded, recognized that many of
the design challenges faced and successfully solved in the world of J2EE application development were
still relevant issues in the world of RIA development. We came to this realization back in the days of
RIA development with Flash, Flash Remoting, and J2EE—a period of RIA history that we'll look back
upon with the same fondness and nostalgia as a C++ programmer has for 6809 assembly language.
Borrowing a subset of a collection of design patterns advocated by Sun Microsystems as the Core J2EE
Pattern Catalog, we first presented these patterns to the Flash community in our book, Reality J2EE:
Architecting for Macromedia Flash MX (Pearson Education, 2003). To accompany the release of Flash
MX 2004, we presented the patterns in a chapter called "ActionScript 2.0 Design Patterns for RIA
Development" in Macromedia Flash MX 2004 ActionScript 2.0 Dictionary (Macromedia Press, 2003).
As the RIA technology platform matured from the design-centric approach of Flash towards the
declarative programming model of Flex, most of the motives for applying these patterns remained.
However, the Flex programming model offered us ever more elegant ways to implement these patterns.
Furthermore, some patterns that we considered hugely valuable to Flash RIA developers (such as the
ViewHelper pattern) became less relevant in the Flex RIA world, allowing us instead to advocate new
Flex-specific patterns of our own, such as the ModelLocator pattern.
At MAX 2004 we announced our decision to release the Cairngorm framework as an open-source
project for Flex; a decision that has led very much to its widespread adoption within the community.
What Cairngorm Teaches You
Cairngorm is a microarchitecture that addresses three key areas that we have always tried to provide as
best-practice recommendations for our customers and partners:
• Handling user gestures on the client
• Encapsulating business logic and server interactions
• Managing state on the client and representing this state to the user interface
Cairngorm offers a microarchitecture (collection of design patterns) that aids us in consistently solving
these recurring design challenges.
As you read this series of articles, you will learn the following:
• How the Front Controller and Command patterns implement a "Service to Worker"
microarchitecture for listening and responding to user requests.
• How the Business Delegate and Service Locator patterns interact in such a way that you can
reuse the business logic and encapsulate it so that it establishes a clear contract between client
and server-side development teams, independent of server-side technical implementations such
as web services, Enterprise JavaBeans, ColdFusion components, or even RESTful architectures
using XML over HTTP.
• How the Value Object pattern from J2EE can collaborate with the Model Locator pattern first
implemented in Cairngorm 0.99 to be an elegant strategy for maintaining a stateful client with a
rich and cinematic user experience.

Current State of Cairngorm


Cairngorm is currently in version 0.99. It never made it to a 1.0 release because iteration::two became
immersed in a trail of acquisitions, first by Macromedia and then by Adobe Systems. Furthermore, with
Flex moving towards a 2.0 release of its own, the introduction of ActionScript 3.0, a number of
improvements to the underlying Flex application framework, an exciting array of new services
(including Flex Enterprise Services), and the evolution of the Cairngorm Committee—now comprised
of a committed core of Adobe consultants and Adobe engineers, as well as numerous community
members behind it—Adobe Consulting is focused on aligning a comprehensive Cairngorm 2.0 release
that leverages the underlying Flex 2.0 framework.
The core Cairngorm concepts remain the same, however. Only the underlying implementation changes
due to additional thought leadership and best practices on how to leverage Flex 2.0 features such as
Flex Data Services and Flex RPC Services within a Cairngorm application. For those working with
Flex 2.0 in Labs, we will also make available regular alpha releases of Cairngorm 2.0.
Note: In the final article of this series, I explore the criteria you can follow to decide when to use
Cairngorm—and when not to use it. We do not advocate for a second that Cairngorm is the only way to
build Rich Internet Applications. Nor do we even suggest that our best practices are the only best
practices. In fact, others may promote best practices that seem to contradict what Cairngorm suggests.
All we ask is that you first try to understand the problems that Cairngorm tries to solve before
preemptively solving them with Cairngorm. If you are learning Flex for the first time and
consequentially building one of your first Rich Internet Applications, I strongly suggest that you
become comfortable with the myriad of new tools and techniques that the technology and platform
offer you before complicating your learning curve with Cairngorm.
This is not to say that Cairngorm is complex. On the contrary, it is important that you be confident and
comfortable building simple RIAs that do not require the benefits of a technical architecture such as
Cairngorm before taking advantage of the benefits that Cairngorm prescribes.
Parts 2–6 will ensure that both seasoned and novice Flex developers understand the RIA challenges that
created the problems for Cairngorm to solve. We want to explain as clearly as we can, and with detailed
code-level examples, the elegant way in which Cairngorm can help you solve them.

Where to Go from Here


The aim of this article was to introduce you to the Cairngorm framework by clarifying the ambiguity
around the definition and usage of frameworks, why you might use a framework, and the origins and
the future of the Cairngorm framework.
Cairngorm is an architectural framework that provides a suggested implementation of a technical
architecture upon which you can build your own, more complex, application-specific architectures.
By basing your application on the Cairngorm architecture, however, there are some generic and
fundamental design challenges that you won't have to solve by yourself while leveraging the benefits
inside Flex, such as how to handle user gestures in an elegant fashion, how to handle server interaction
and business logic in an elegant and scalable fashion, and how best to manage state on a rich and
immersive client application.
I gave a brief overview of the engineering discipline of software design patterns and how iteration::two
borrowed those that were useful to us as J2EE developers, and which are still useful for our RIA
development. Having an aerial view of the technical architecture usually helps developers identify
recurring collaborations of design patterns. The concept that such collaborations, known as
microarchitectures, exist is the foundation of the Cairngorm framework.
When consulting, I often say that the difference between theory and practice is that, in theory, there's no
difference between theory and practice. In Part 2, I depart from the discussion of context and
background of design patterns and microarchitecture, and instead present Cairngorm in terms of
providing four key benefits:
• Maintaining state on the client
• Architecting the user experience
• Implementing feature-driven development
• Invoking server-side services
In Part 2, you'll get a hands-on feel for the ways we leverage the Cairngorm framework in application
development, the problems that Cairngorm solves, and the ease with which you can consistently deliver
highly scalable, maintainable, and robust Rich Internet Applications with Flex.
Developing Flex RIAs with Cairngorm Microarchitecture – Part 2: Keeping State on the Client

Developing Flex RIAs with Cairngorm Microarchitecture – Part


2: Keeping State on the Client
Steven Webster
Adobe Consulting
www.richinternetapps.com

Table of Contents
1. Introduction
2. The Cairngorm Store: Four Key Challenges
3. Keeping State on the Client
4. Keeping a Consistent Object Model Between Flex and Java
5. Binding the Model and View Together
6. Enter the Model Locator Pattern
• Printable version
• Send feedback
• Get an e-mail update of new articles
• Take a survey

Comments
Created:
20 February 2006
User Level:
Intermediate

In Part 1 of this series, I introduced Cairngorm, a lightweight technical architecture that simplifies
much of the recurring complexity in developing large-scale rich Internet applications, called enterprise
RIAs.
In this article, I describe the challenges faced in developing enterprise RIAs—specifically, how to keep
state on the client. I explain this in the context of an e-commerce application called the Cairngorm
Store. You'll learn about two fundamental patterns in the Cairngorm architecture: the Value Object
pattern and the Model Locator pattern. By the end of this article, you will understand the clarity you
can achieve within your own Flex application development by using these patterns.

Requirements
To complete this tutorial you may want to install the following software and files so that you can follow
along:

Macromedia Flex
• Try
• Buy

Cairngorm version .99


• Download Cairngorm version .99
Read Developing Flex RIAs with Cairngorm Microarchitecture – Part 1: Introducing Cairngorm before
reading Part 2.

Introducing the Cairngorm Store


The Flex Store application showcases the features of the Flex application framework. It demonstrates
how to use various layout containers, navigator containers, controls, effects, data binding, the Drag-
and-Drop manager, form validation, and the History manager. Furthermore, Flex Store articulates the
component-development model of Flex, showing how to create loosely coupled components that
integrate through an event-driven architecture. The Flex Store application is an excellent way to
become familiar with declarative layout using MXML and business logic development using
ActionScript.
With the Cairngorm Store (see Figure 1), I take this familiar application and completely rebuild it as an
enterprise rich Internet application—an application that is rapid, scalable, and maintainable—through
Cairngorm.

Figure 1. The Cairngorm Store


The Cairngorm Store borders on the complexity of a rich Internet application that would benefit from a
Cairngorm architecture. Indeed in Part 3, I demonstrate this tipping point by showing how, within the
rearchitected Cairngorm application, you can add new functionality easily, more predictably, and with
significantly less development risk than if you were to attempt to add functionality to a non-Cairngorm
code base.

The Cairngorm Store: Four Key Challenges


Instead of an academic discussion of design patterns we selected for Cairngorm, I will explain the
common high-level challenges that often occur when developing rich Internet applications and how to
achieve these solutions with a Cairngorm development process. By describing the development
process, I also explain the various constituent design patterns used in the Cairngorm framework.
A good technical architect first sees application development as a solution to a business problem, then
as a system that realizes this solution, then as a technical architecture for the custom software in the
system, and finally as the detailed class-level implementation of that technical architecture.
The approach taken here in Cairngorm and Cairngorm Store gives you clarity from 35,000 feet before a
deep dive and race along the terrain at the code level.
From a high level, there are four key challenges that the Adobe Consulting team faces, whether
building mortgage calculators, retirement planners, online banks, single-screen checkouts, full e-
commerce applications, or interactive maps. These challenges are as follows:
• Keeping state on the client
• Architecting the view
• Driving feature-driven development
• Invoking server-side services
The challenges and requirements for the Cairngorm Store are no different.
The client presents the products to sell to the customer, the shopping cart remembers what the user
purchased, and the user must complete multipage application forms during the checkout process.
Throughout this entire process, your application must maintain state on the client.
The single-screen user experience has a number of different on-screen components. It has both
graphical and list-based views of the products for sale, detailed product information, a shopping cart
that the user can add to or drag products to, and a series of forms that the user must fill in to fulfil his or
her order. You must architect the view.
There are a number of features that users demand in the application. The users must be able to do the
following:
• View all products and get detailed information for any selected product
• Add products to, or remove products from, their shopping cart
• Purchase products in their cart
• Proceed to and complete a checkout process.
These features drive your development.
Finally, the products that the application sells change as inventory changes. Your application must fetch
product information from a server-side infrastructure capable of pulling products from an inventory
database. Furthermore, when customers place orders, your application must persist the orders in
enterprise systems by committing these orders to a database or a system such as SAP. Your application
must integrate with and invoke server-side services.
As you can see, the Cairngorm Store—though unique in its business domain, product selection, and
look and feel—is just like any other rich Internet application when studying it against the four key
challenges.
In this article, I take a look at the first of these four key challenges: keeping state on the client.
Keeping State on the Client
One key shift in mindset when you move from the development of web applications to rich Internet
applications is that the client is stateful.
Web application developers are all too familiar with the stateless request/response approach. Therefore,
they have created various approaches for maintaining state on the client. Whether you continually stuff
data into an HTTP request as the client and the server exchange pages, or you use URL encoding or
cookies to keep some limited state information on the client, or you take advantage of abstractions of
these features such as J2EE sessions, the typical application developer's is to maintain state on the
server, and make it available to the client.
With RIAs however, web application developers can break free from the shackles of HTTP request and
response. No longer do you have to concoct solutions for the stateless client because the client is indeed
stateful. If you have been building desktop or rich-client applications with technologies such as Swing
or AWT, for instance, you'll shrug your shoulders right now because all of this will sound all too
familiar—it is.

Difference Between State and the Model in MVC


Many developers are familiar with the concept of MVC or Model/View/Control in application
development, and wonder where state fits into this discussion. Quite simply, the state is the model. As
obvious as this may sound, it presents some further common challenges to solve in the implementation
of the model in an RIA.
First, resist the opportunity to scatter state all over your application as strings, numbers, Booleans, and
all manner of other primitive objects. It is not my purpose here to advocate best practice object-oriented
development. Indeed, that you accept the benefits and practice the principles of OO are almost
prerequisites to understanding this article.
However, I strongly advocate that the client hold the data—as state, model, or whatever you want to
call it, as objects that have semantic meaning. What is semantic meaning in this context? I mean that if
you sell fly-fishing flies online, your object model should include "flies," "patterns," "hooks," and
"hackles." If you sell mortgages, your object model should include "products," "rates," "repayments,"
and "terms." If you sell maps, your object model likely includes "routes," "waypoints," "points of
interest," and "gas stations."

Synchronizing Client and Server State


One challenge is relatively unique to the stateful client of a rich Internet application: The state on the
client usually reflects the state held on the other side of the wire, in the server middleware. Let's
examine this design problem some more.
In server-side application development, one key challenge is that state often sits within two tiers of an
application architecture: the business tier and the integration tier.
The integration tier usually contains databases, mainframes, message queues, ERP solutions, CRM
systems, and other enterprise information systems that hold data on the objects and process particular to
a business domain.
In enterprise application development, these systems are typically aggregated and presented to users
through a middleware tier, also called the business tier. Many solutions address some of the challenges
of keeping state consistent across the two tiers. First of all, the representation of data in these tiers may
be dramatically different. For instance, the entities, relationships, views, and queries that exist in a
relational database solution must be mapped from a relational model in a database to an object model in
the middleware business tier. You can use technologies such as Enterprise JavaBeans, Hibernate (H8),
and ADO.NET to map data across these architectural tiers.
Irrespective of the solution chosen, the application developer assumes a great deal of responsibility in
ensuring the consistency of state across these tiers. As soon as you keep the same information in two
places, there is a risk that changes to it in one place are not reflected in another place, or that changes in
one place overwrite changes in another place. Suddenly, the developer must care about concurrency,
locking, transactions, rollback, and other approaches for ensuring that the model is consistent in these
different places in the architecture.
As RIA developers, you are abstracted from the complexities between the business and integration tier;
your concerns focus more on how to ensure that the model in the business tier is consistent with the
model in the presentation tier.
You can achieve this most easily by ensuring that you have a consistent object model on the client and
server, and that you minimize the effort required to keep these object models synchronized.

Introducing the Value Object / Data Transfer Object Pattern


Whenever you want to represent the value of things on the client, you can do worse than to create
classes or objects that represent the values of those things. For instance, in Cairngorm Store, one thing
that you must represent is the products in our store. Each product has a number of attributes: name,
description, price, an associated image for the detailed view, and an associated thumbnail image for the
catalog view.
These value objects play a dual role in a rich Internet application, however. In addition to keeping the
value of an item on the client, they are useful structures with which you can exchange or transfer data
between different tiers in an application. In server-side development, consider a strategy in which you
query a database using SQL, receive a result set, and then transform that result set into a collection of
value objects representing the things you have pulled from the database.
By passing collections of these value objects between application tiers, you insulate each tier of the
application from the underlying implementation of its neighboring tiers. The middleware need not care
whether these value objects were created from a SQL query, stored procedure call, message queue, or
web service call. By reusing these value objects, you decouple architecture by transferring data
between tiers as objects with business meaning ("Products," "Fish," "Maps") rather than technical
meaning ("RecordSets," "ResultSets," "Data Sets"). This has led to calling the Value Object pattern the
Data Transfer Object pattern instead.
We conceived Cairngorm before the term data transfer object (DTO) became popular, so I call the
business objects value objects or VOs.
For example, look at the VOs in the Cairngorm Store application, which reside in the
org/nevis/cairngorm/samples/store/vo package:
class org.nevis.cairngorm.samples.store.vo.ProductVO implements ValueObject,
Comparable
{
public static var registered:Boolean = Object.registerClass(
"org.nevis.cairngorm.samples.store.vo.ProductVO", ProductVO );

public var id : Number;


public var name : String;
public var description : String;
public var price : Number;
public var image : String;
public var thumbnail : String;
}

This is not rocket science. The ProductVO is nothing more than a collection of attributes that describe
what makes a Product a product. Whenever you keep state on the client about Products, keep it as
instances of the ProductVO. If the application must know what the "currently selected product" is, store
that information on the client as a ProductVO instance. If the application needs to retain a list of the
products in a customer's shopping cart, store that information on the client as a list of ProductVO
instances.
Furthermore, if you have to transfer products from the server (and we do, but more on that later) or if
you ever have to transfer products back to the server, transfer that data back and forth as value objects.
Others might say that you're using data transfer objects, because you are. They're the same thing,
remember?

Keeping a Consistent Object Model Between Flex and Java


When you develop middleware, a key artifact from the development process is typically a well-defined
object model. In J2EE application development, there is often a package of Java value objects already
on the server that correspond exactly to the value objects required on the client.
In this case, the Flex server does some pretty significant heavy lifting for the application. If you want to
pass ActionScript value objects into Java, Flex can automatically create the equivalent Java objects on
the server side for those objects that you placed on the client side. Similarly, as the Java middleware
returns Java value objects to the client, Flex ensures that by the time the RIA uses these objects on the
client side, Flex has already translated them into the equivalent ActionScript value objects.
Even more powerfully, if the objects are not just single value objects but complex graphs of value
objects, Flex does all the work associated with traversing the graph of objects—not only translating the
objects but maintaining the relationships between objects. Thus, when you have a ShoppingCartVO
that contains a list of ProductVO objects, and each ProductVO contains a list of AddressVO objects
(for delivery and invoice addresses) and an optional DiscountVO object, Flex ensures that the
composition of objects stays consistent when passing it between the RIA client and middleware server.
To allow Flex to map between client-side and server-side value objects, you must provide some hints to
the Flex server about the relationship between the classes. In Cairngorm, you achieve this by
advocating that each and every instance of a value object class contains the following:
public static var registered:Boolean = Object.registerClass(
"org.nevis.cairngorm.samples.store.vo.ProductVO", ProductVO );

This line ensures that a ProductVO class on the client maps to the Java class ProductVO.java that
resides in the package org.nevis.cairngorm.samples.store.vo.ProductVO on the
server.

Using XDoclet2 with ActionScript


XDoclet2 is a java-driven ActionScript code generator. Joe Berkowitz of Allurent created a labor-
saving, open-source project for creating ActionScript value objects from their Java counterparts. You
can find more information on the project, including a link to the source code on SourceForge, at
www.allurent.com/joeb/xdoclet2.
To recap, value objects ensure that you do the following:
• Adhere to the best practice of representing client-side data with a meaningful object model
• Maintain a consistent object model on the client and server
• Leverage the capabilities of the Flex server to translate value objects between Java and
ActionScript as they "cross the wire" between client and server
Getting data to the client that is consistent with the server is only the first part of the problem. What do
you do with the client-side data and where you keep it to enable you to accomplish this task?

Binding the Model and View Together


One of the primary reasons for wanting data in the presentation tier of an n-tier application is to display
that data. Furthermore, the R in RIA is about presenting data in a rich and immersive way.
One of the unsung features of the Flex application framework is the data binding capabilities of Flex.
Data binding allows two objects to act as a source and a destination. Changes to the source object are
reflected immediately in the destination object. When the destination object is a visual component and
the source object is client-side data, you suddenly have a powerful means for ensuring that changes to
the client-side state are rendered to the user in real time. The user's view is never stale; the model (the
client-side state) is always notified by the view (the user interface) if you have used data binding to
bind the model and view together.
At Adobe Consulting, we witnessed development teams convolute solutions for updating the user
interface whenever the underlying model changed. Furthermore, these teams became tangled in a mess
pretty quickly when displaying data in different parts of the view in different ways. Let's say you have a
series of numbers that have been updated on a server. Depending on a user's location in the application,
this may cause their table or graph display to update or update data in a dashboard summary about key
assumptions for a business. By refactoring architecture towards keeping the data in a client-side model,
and leveraging data binding between this model and the different view components, you eliminate
much of the complexity around this kind of interactivity and responsiveness in an RIA.
Furthermore, we found that each developer kept the client-side state he needed for his parts of the
application development (in his parts of the code base). Consequently, when another developer needed
to use that data in another part of the application, she would have to create convoluted and complex
solutions to ensure the data was visible from more than one place.
Often we found that developers referenced other data with long chains of component references, such
as mx.core.Application.application.storeView.textualList.productGrid.
Such strategies are incredibly brittle to change—adding or removing any components (storeView,
textualList) would require that a developer update any references to productGrid.
Additional strategies include passing data up and down through MXML component instantiations.
Consider the following graphical representation of MXML components, where data is in a leaf node of
the tree and is required in another developer's leaf node. The only solution is to find a common
branching point for both leaf nodes and then, from that branching point, pass the data down through the
component chain with component instantiations, as follows:
<myView:MyComponent data="{this.data}" />
Once again, this is a strategy that is incredibly brittle to changes in the implementation of the view. It
leads to regular errors because it incorrectly passes data down the chain somewhere. Debugging these
errors is a laborious job of tracing the component paths to confirm that data has been correctly passed
between components. It's a frustrating task.

Enter the Model Locator Pattern


Watching developers fall repeatedly into these traps, the Adobe Consulting team conceived the Model
Locator pattern as a best practice for Flex developers to adopt. The Model Locator pattern is unique
because it is not a pattern we borrowed from the Core J2EE Pattern catalog. Instead, we created this
pattern particularly for Flex application development. Our motivation was to have a single place where
the application state is held in a Flex application and where view components are able to "locate" the
client-side model that they wish to render.
Our Model Locator pattern strategy encourages the use of data binding so that view components bind
directly to the client-side state held in the single instance of the ModelLocator class. In this way,
whenever the model is updated in ModelLocator, all view components binding to the model receive
notifications (through the underlying data-binding mechanism) and update themselves to render the
new model on the client.
In Cairngorm, we provide a marker interface for the Model Locator pattern, and in the Cairngorm Store
we have a single class that implements this marker interface,
org.nevis.cairngorm.samples.store.model.ModelLocator.
As you take this opportunity to review the source for this ModelLocator class, let me point out a
few examples of its usage. In the Cairngorm Store, there is always a notion of the "currently selected
product." This is the item that the user has selected. The application stores an instance of a ProductVO
in the model locator, uses the selectedItem property in the application to render the
ProductDetails panel, and uses the property to decide what to add to the shopping cart when the
user presses the Add to Cart button.
See the ModelLocator source in the following entry:
public static var selectedItem : ProductVO;

In Part 3 of this series, you will learn how to use data binding to ensure that the currently selected item
always appears in the product details view.
Additionally, through ModelLocator, you can find the list of products for sale in the Cairngorm
Store from anywhere in the application by storing an ArrayList of these products on ModelLocator,
as follows:
public static var products : Array; // containing ProductVO objects

Also notice how the application stores constants in ModelLocator. In this application, these
constants allow you to track the state of the application (there are three possible states) as follows:
public static var workflowState : Number;

//------------------------------------------------------------

public static var VIEWING_PRODUCTS_IN_THUMBNAILS : Number = 1;


public static var VIEWING_PRODUCTS_IN_GRID : Number = 2;
public static var VIEWING_CHECKOUT : Number = 3;

Finally, you have a complex ShoppingCart component that encapsulates all the functionality
associated with adding and removing items to a list of items that the customer may want to purchase.
You stored the shoppingCart instance on the ModelLocator and initialized it within the
ModelLocator in the initialise() method.
Having all the attributes on the Model Locator pattern as static attributes ensures that the Model
Locator pattern is a simple implementation of a singleton. You ensure, for instance, that one and only
one instance of a ShoppingCart exists per user.
The single instance of ModelLocator is initialized immediately when the main application is
initialized. In the Main.mxml file (the entry point for the Cairngorm Store) you have declared the
following method as a handler for the creationComplete event on the main Application tag:
<mx:Script>
<![CDATA[

import org.nevis.cairngorm.samples.store.model.ModelLocator;

private function onCreationComplete() : Void


{
ModelLocator.initialise();
}

]]>
</mx:Script>

This code ensures that all the client-side state (such as our shopping cart) correctly initializes when the
application starts.
Next, I'll take a look at data binding to the ModelLocator in greater detail. But to whet your
appetite, let me say that when you create components that rely upon client-side data rather than adopt
any of the convoluted strategies that result in a brittle implementation of the view, you can instead
locate client-side state by binding to the singleton ModelLocator from any component in the
application.
By way of example, we have a SideArea.mxml component in the Cairngorm Store that contains the
ProductDetails and ShoppingCart components. As you'll see in Part 3, ProductDetails requires the
currently selected item, so that it can display the name, description, price, and image of the item the
user has selected. Because the currently selected item is stored in ModelLocator as an instance
Product VO called selectedItem, you can pass this item into our ProductDetails component
as shown below:
<details:ProductDetails
id="productDetailsComp"
width="100%" height="325"
currencyFormatter="{ ModelLocator.currencyFormatter }"
selectedItem="{ ModelLocator.selectedItem }"
addProduct="addProductToShoppingCart( event )" />
The highlighted line of code shows that within the ProductDetails.mxml file, there is an attribute called
selectedItem that is an instance of a Product VO. You have just used data binding (the curly brace
notation) to ensure that anytime selectedItem on ModelLocator is updated, the
ProductDetails view updates accordingly. I'll explore that mechanism more in Part 3.

Where to Go from Here


In this article, I identified a number of challenges that are consistent across rich Internet applications,
regardless of the business domain of the application. I'll use these challenges to explore the Cairngorm
development model in greater detail.
Specifically, I introduced the first of these challenges: keeping state on the client. I also observed how
the terms "state," "model," and "client-side data" are interchangeable in the development community.
RIAs let you to break free of the request/response paradigm of HTML web applications. They help you
keep data on the client as the user uses the application. Now you assume a certain degree of
responsibility for that client-side state.
With applications, you must address data integrity and consistency issues on the server—between the
integration and business tier and, to a lesser extent, when sharing data between the business and
presentation tier of an RIA. However, you recognize that wherever an object model already exists on
the client, you can take advantage of the Flex server capabilities to map between the ActionScript and
Java world, and keep a consistent object model on the client and server. Irrespective of this,
representing client-side state as first class objects with semantic meaning—rather than a mindless
collection of strings, numbers, and Booleans—dramatically improves the readability and maintenance
of your code base.
Therefore, I presented the Value Object (VO) pattern in Cairngorm, also referred to in the software
engineering community as a Data Transfer Object (DTO) pattern.
Having a sensible way of representing the client-side object model guarantees that developers will be
sensible about where they keep that state on the client, how they share the client-side state between
different components (who may have different ways of rendering the state), or how they ensure that the
view is always showing the most up-to-date rendering of the state.
Consequently, I presented the Model Locator pattern, first introduced in Cairngorm, as a strategy for
ensuring that state is held in a singleton class that can be located from anywhere in your Flex
application architecture. The singleton nature of the Model Locator pattern ensures that you don't suffer
from duplicate state on the client, gives a large development team a consistent place to expose and
share application-level state as instances of value objects, while ensuring that developers leverage the
powerful data-binding capabilities of Flex to ensure that the view is notified when the model has
changed.
In Part 3, I'll focus your attention a little more on the view. I'll explore in greater depth how to leverage
Flex data binding with state stored on ModelLocator before exploring more of the Cairngorm
framework.
Developing Flex RIAs with Cairngorm Microarchitecture – Part 3: Architecting the View
Developing Flex RIAs with Cairngorm Microarchitecture – Part
3: Architecting the View

Steven Webster
Adobe Consulting
www.richinternetapps.com

Table of Contents
1. Introduction
2. Architecting the View
3. Binding the Model to the View
4. Best Practices for MXML Development
• Printable version
• Send feedback
• Get an e-mail update of new articles
• Take a survey

Comments
Created:
27 February 2006
User Level:
Intermediate

In Part 2 we focused on managing state within rich Internet applications as you learned how to use the
Value Object and Model Locator patterns. In Part 3, the aim is to reach out to your application's users.
While the concept of holding state on the client empowers developers, it means nothing to users unless
they can visualize and interact with that state in a meaningful way.
The Cairngorm Store must display product images so that users can select products and get further
details on them, drag and drop products into their shopping cart, and purchase these products in a
checkout process. In this article, you'll explore how to architect the view and deliver rich and
immersive experiences to your users using the Cairngorm framework. You'll pick up some best
practices you can use to structure your MXML code and files, even though Cairngorm does not
prescribe any specific way to structure your view.

Requirements
To complete this tutorial you may want to install the following software and files so that you can follow
along:

Macromedia Flex
• Try
• Buy
Cairngorm version .99
• Download Cairngorm version .99

Prerequisites
Read the previous articles in the series, starting with Developing Flex RIAs with Cairngorm
Microarchitecture – Part 1: Introducing Cairngorm before reading Part 3.
Page 1 of 4
Next Page

About the author


Steven Webster is the practice director for Rich Internet Applications at Adobe. Previously, Steven was
the technical director at iteration::two, a world-leading Rich Internet Application consultancy based in
Edinburgh, Scotland. Steven is the author of Reality J2EE: Architecting for Flash MX and coauthored
ActionScript 2.0 Design Patterns for Rich Internet Applications (ActionScript 2.0 Dictionary) and
Developing Rich Clients with Macromedia Flex with Alistair McLeod. Steven speaks regularly at
conferences and user group meetings on technical and business aspects of RIAs. Steven is the core
contributor to the open-source Cairngorm project, a microarchitecture for RIAs based on J2EE
patterns which was innovated by iteration::two over a number of Flash and Flex RIA developments.

Architecting the View


Perhaps the first and most important thing to understand about architecting your view logic with
Cairngorm is that Cairngorm doesn't actually care! One key value of the Cairngorm architecture is that
it is lightweight and places little imposition on the Flex developer, so as not to stifle individual
technical flair.
Rather, Cairngorm offers clear integration points between the "rich" and the "application" in RIA.
The user experience must represent the application's current state by displaying particular screens and
rendering the model in a specific way. This might mean showing the products in Cairngorm Store as
graphic thumbnails instead of tabular data, deciding which subset of the products to make visible based
on a slider that specifies a price range that the user selects for the products, or recognizing that the user
has finished shopping and guiding them to complete the checkout process. You make decisions on the
dynamically rendered views by integrating the view with the model. I've already discussed Value
Objects and the Model Locator pattern in detail, but I will complete this part of the puzzle shortly.
A rich Internet application is a communication between the user and the application. The best form of
that communication is bidirectional. While the user experience must "speak" to the user by rendering
the view according to the state of the model, the user experience needs to "listen," hearing what the
user wants to do with the application and responding accordingly. In this case, user requests are called
gestures; user requests gesture to the application what the user wants to do as he or she clicks buttons,
drags objects, completes and submits forms, and so forth. Responding to user gestures (by listening to
the user), doing something on behalf of the user, and then "speaking" back to the user by updating the
view (or, more correctly, updating the model, which you might now recognize automatically updates
the view) becomes the flow of conversation between user and RIA. Elsewhere in this article, I'll
explain the Cairngorm design patterns and architecture that can mediate the conversation between user
and RIA.
Moving on, the structure of the article is as follows. I'll complete the discussion of the Model Locator
pattern by explaining how you build the view to take advantage of data binding in the Cairngorm Store.
Next, even though Cairngorm does not prescribe the view, I'll offer some advice on best practices for
structuring your view. You can use much of this advice whether or not you're using Cairngorm.
However, if you are using Cairngorm, heeding this advice will help you make architectural decisions
about your MXML components.
Finally, I'll introduce you to a "microarchitecture within a microarchitecture," called the Service to
Worker concept. Service to Worker is a collaboration of design patterns that the Adobe Consulting team
first advocated within Cairngorm as a way to mediate the essential conversation between the user and
the application on a feature-by-feature basis.

Binding the Model to the View


By now, you have an understanding of the Model Locator as a singleton that you can use to store and
retrieve all states in your rich Internet application. Furthermore, and as much as is appropriate, your
application holds state as Value Objects (VOs) and collections of Value Objects, rather than as
primitive types (strings, numbers, and Booleans), which rarely communicate the same information to
fellow application developers.
Now I'll take a detailed look at the Model Locator strategy and the challenges it can face, and how you
can leverage the powerful data binding capabilities of the Flex framework as you collaborate with the
Model Locator and Value Object patterns.
The Product Details panel in the Cairngorm Store (see Figure 1) shows the detailed product
information for the product that the user last selected by clicking a product in the graphic or text
product view.
Figure 1. Detail view of a product
The entry point for the Cairngorm Store is the Main.mxml file, which partitions the design into two
components:
• BodyPanel: Panel that represents the main body of the application and renders the graphical
and textual product views, and the checkout process
• SideArea: Vertical box container that holds the ProductDetails and ShoppingCart
components
Look at the instantiation of the SideArea component. As in Part 2, this example uses data binding to
bind the details that the ProductDetails component renders to the selectedItem instance of a
ProductVO value object held in ModelLocator:
<details:ProductDetails
id="productDetailsComp"
width="100%" height="325"
currencyFormatter="{ ModelLocator.currencyFormatter }"
selectedItem="{ ModelLocator.selectedItem }"
addProduct="addProductToShoppingCart( event )" />

Open the ProductDetails.mxml file to see the implementation of the component. Note the judicious use
of data binding to render the individual elements of the selectedItem instance:
<mx:Script>
<![CDATA[[

// set during MXML instantiation


public var selectedItem : ProductVO;

]]>
</mx:Script>

<mx:HBox>

<mx:Canvas
width="150" height="140"
clipContent="false">

<mx:Image
id="image"
source="{ selectedItem.image }"
mouseDown="beginDrag();"
mouseOverEffect="big" mouseOutEffect="small" />

</mx:Canvas>

<mx:VBox
width="100%" height="100%"
styleName="productDetailsTitle">
<mx:Label
id="name"
text="{ selectedItem.name }"
styleName="title" />
<mx:Label
id="price"
text="{ selectedItem.price}"
styleName="price" />
</mx:VBox>
</mx:HBox>

<mx:Text
id="description"
width="100%" height="100%"
text="{ selectedItem.description }"/>

</mx:VBox>

With these data bindings in place, any changes to the selectedItem instance held in
ModelLocator causes the binding to execute in the <details:ProductDetails /> instance,
updating the selectedItem attribute of the ProductDetails component. This update causes
each binding on selectedItem in ProductDetails to execute, resulting in an update to the
image, name, description, and price to reflect the attributes of the newly selected item.
This is the basic premise of Flex data binding. Cairngorm brings an approach for ensuring that dynamic
data displayed in your MXML comes from ModelLocator, not elsewhere.
The final piece of the puzzle is how to update the selectedItem instance in ModelLocator. The
ProductsAndCheckoutViewStack component shows the following component instantiations:
<productview:GraphicalProductList
id="graphicalProductList"
products="{ ModelLocator.products }"
selectedItem="{ ModelLocator.selectedItem }"
select="ModelLocator.selectedItem = event.target.selectedItem;" />

<productview:TextualProductList
id="textualProductList"
products="{ ModelLocator.products }"
selectedItem="{ ModelLocator.selectedItem }"
select="ModelLocator.selectedItem = event.target.selectedItem"
currencyFormatter="{ ModelLocator.currencyFormatter }" />

Both components responsible for graphical and textual rendering of the product catalog expose select
events, which the components dispatch when the user clicks a new product. To handle these events, as
shown in the highlighted code above, simply update the selectedItem instance on
ModelLocator to a ProductVO value object representing the item that the user has just selected.
Since the model notifies the view of this change through data-binding means that the application
developer does not need to worry about implementing of the view or updating the many different
elements of the view to reflect the model change.
See this demonstrated in the "single model, multiple view" example by looking more closely at the two
components above: the GraphicalProductList and the TextualProductList components.
In the instantiation of these components (both have a products attribute), both components bind their
individual products attributes to the same model; that is, to ModelLocator.products.
ModelLocator.products is an array list of ProductVOs, as you may recall from Part 2 (or by
reviewing the source code).
In the GraphicalProductList component, this list of products becomes the dataProvider for
a TileList, which has its own cell renderer (ProductThumbnail) capable of rendering a
ProductVO:
<mx:TileList
id="tileListComp"
width="100%" height="100%"
dataProvider="{ products }"
cellRenderer="org.nevis.cairngorm.samples.store.view.productview.ProductThumbna
il"
itemWidth="120" itemHeight="116"
dragEnabled="true"
change="updateSelectedProduct( event );"
borderStyle="none" />

Meanwhile, the TextualProductList component does nothing more than pass the list of ProductVOs to
the dataProvider of a DataGrid, which renders the list of ProductVO instances accordingly:
<mx:DataGrid
id="dataGridComp"
dataProvider="{ products }"
change="updateSelectedProduct( event );"
dragEnabled="true"
width="100%" height="100%">

This example clearly demonstrates the Model Locator strategy in action. Each view component
declares and renders its own local model, so that each is completely oblivious to the application
running within a Cairngorm architecture. Only at the very highest level of the component's usage—
most often in the entry point MXML file—do you couple the component's usage to Cairngorm by
populating and binding its local model to a model residing on ModelLocator.

Best Practices for MXML Development


The preceding discussion touches on best practices that Adobe Consulting urges developers to adopt
when implementing their own user experiences with MXML.
One key best practice is "to develop with components in mind." With MXML, it is incredibly easy to
create components that extend base tags with application-specific functionality. If you have ever had to
review someone else's MXML code and tried to trace your way through hierarchies of VBox controls
containing HBox controls containing VBox controls containing TileList controls containing VBox
controls, and so forth, you will quickly realize the value in creating components that have semantic
meaning.
If you review the Cairngorm Store's code, you will quickly be able to cross-reference MXML
components with their visual renderings on the screen. By creating components such as Main,
SideArea, ProductDetails, ShoppingCart, ProductDetails, ProductThumbnail,
GraphicalProductList, TextualProductList, ProductAndCheckoutViewStack,
and so forth, you will be able to navigate your own source code more easily, never mind someone else's
code.
When designing with components in mind, learn to use the events infrastructure within Flex to couple
your components loosely. For instance, create your own events, which describe what happens at the
user level, not at the Flex framework level. Consider the difference between a button within a VBox
control having some code within a click="" event handler, versus a component called
ShoppingCart that responds to an event called productAdded. When you create your own
events, broadcast these events from within your components and handle these events accordingly. Your
code base will become much more maintainable.
Again, consider the ProductDetails component in the Cairngorm Store, which is an application-
specific rendering of a Panel component that broadcasts an event whenever the user clicks the Add to
Cart button:
<mx:Panel
xmlns:mx="http://www.macromedia.com/2003/mxml"
xmlns:details="org.nevis.cairngorm.samples.store.view.productdetails.*"
title="Product Details"
styleName="productDetails">

<mx:Metadata>
[Event("addProduct")]
</mx:Metadata>

<mx:Script>
<![CDATA[

private function addProduct() : Void


{
var event : Object = new Object();
event.type = "addProduct";
event.product = selectedItem;
event.quantity = quantity;
dispatchEvent( event );
}

: : :
<mx:Button
label="Add to Cart"
click="addProduct();" />

</mx:Panel>

Here the click event of the button is mutated into an addProduct event out of the component.
Furthermore, the event has the selectedItem (the product to add) and the quantity attribute
associated with it on the ProductDetails component, describing how much of the product the user
wishes to add to the shopping cart.
Consequently, when you create an instance of the ProductDetails component (in SideArea.mxml)
you can handle the event in a much more meaningful way:
<details:ProductDetails
id="productDetailsComp"
width="100%" height="325"
currencyFormatter="{ ModelLocator.currencyFormatter }"
selectedItem="{ ModelLocator.selectedItem }"
addProduct="addProductToShoppingCart( event )" />

Although this advice is in no way specific to Cairngorm application development, following this advice
improves the clarity of your application development and makes it easier for you to recognize
integration points between your MXML and ActionScript implementations of the view and any
underlying business logic applied throughout the Cairngorm skeleton.

Where to Go from Here


This article focused on understanding how to construct a view using the building blocks of MXML and
ActionScript. More importantly, I showed how to build this view on the underlying architecture of the
Cairngorm skeleton.
By now you understand how to manage client-side state using the Model Locator and Value Object
patterns. Furthermore, although I've given some guidance and best practices to consider when
architecting your view, such as the MXML and ActionScript classes that describe the user experience,
Cairngorm makes no assumptions and imposes no restrictions on how you choose to architect your
view.
I've discussed how to implement the view and keep state on the view. In Part 4 I'll discuss how to
implement features with the addition of business logic within commands—the "application" in rich
Internet application.

Developing Flex RIAs with Cairngorm Microarchitecture – Part


4: Feature-Driven Development

Steven Webster
Adobe Consulting
www.richinternetapps.com

Table of Contents
1. Introduction
2. Engaging in Rich Conversations
3. The Service to Worker Microarchitecture
4. Service to Worker: Mapping User Gestures and System Occurrences to Events
5. Service to Worker: Listening for Events with the Front Controller
6. Service to Worker: Broadcasting Cairngorm Events with the Event Broadcaster
• Printable version
• Send feedback
• Get an e-mail update of new articles
• Take a survey

Comments
Created:
6 March 2006
User Level:
Intermediate

Part 3 explained how to construct the user experience using MXML and ActionScript and, most
importantly, explored an area of application development where Cairngorm imposes itself least—and
where it provides the greatest degree of flexibility. After all, the user experience differentiates rich
Internet applications (RIAs) from other applications, and any attempt to impose a structure on
constructing the view limits the richness of the application.
If a rich Internet application is a conversation between man and machine, then Cairngorm is the
interpreter. So far, I have described how Cairngorm enables the machine to talk to the user as it renders
the application's state in a dynamic, visual way. Now consider the more important aspect of
communication: listening (rather than talking). In this article, I explore the design patterns that
Cairngorm uses to listen to the user; through user gestures, I describe how Cairngorm understands what
the user wishes to do in the application.
In the Cairngorm Store, a user can browse a product catalog, select products, get details on selected
products, drag products into a shopping cart, and purchase these products through a checkout process.
Now you'll learn how Cairngorm encourages you to breathe interactivity into rich and immersive
experiences, and how Cairngorm enables your application to respond to your user's every gesture,
whether through a mouse click or keyboard stroke.
This article explores the most fundamental and innovative patterns of the Cairngorm microarchitecture:
the Front Controller, Event Broadcaster, and Command patterns. Understanding how they collaborate
will help you with rapid and consistent application development of RIAs with Flex.

Requirements
To complete this tutorial you may want to install the following software and files so that you can follow
along:

Macromedia Flex
• Try
• Buy

Cairngorm version .99


• Download Cairngorm version .99

Prerequisites
Read the previous articles in the series, starting with Developing Flex RIAs with Cairngorm
Microarchitecture – Part 1: Introducing Cairngorm before reading Part 4.
Engaging in Rich Conversations
When we talk about rich Internet applications, we understand the word rich to describes the
dramatically improved user experience beyond a traditional web application. There is, however, also a
richness in the level of interactivity in the application. Interactivity in this case does not mean
animation and effects, but the extent to which a user can engage with the application as it engages with
the user.
Consider a conversation through a translator. As one person speaks, the translator listens and then
translates a small part of the conversation to a third party. Meanwhile, the speaker waits while the third
party responds, also through the translator. This ineffective communication process repeats itself
between the two parties.
This is analogous to a web application, which is a similar conversation between man and machine. The
web application translates through the stuttered medium of browser to user. Then the user clicks a
button to communicate back to the web application, also through a browser—an ineffective process for
communication.
One of the key benefits of a rich Internet application—beyond the obvious rich user experience—is the
rich communication that can occur between man and machine. Freed from the limits of the
request/response page-driven browsing metaphor, the user can interact at his or her own pace with the
application while the application responds—also at its own pace—to the user. Because control never
passes between man and machine, communication flows better, creating simpler, easier, more effective
and, ultimately, more enjoyable user experiences.
One of the key innovations in Cairngorm leverages a collaboration of design patterns that the J2EE
community used to centralize and manage the man/machine communication in the old-fashioned web
application world and bring it up to date for the more seamless, flowing conversations that rich Internet
applications provide. These design patterns work so well together at solving the higher level problem of
achieving rapport between user and application that they are considered their own microarchitecture:
the Service to Worker microarchitecture.

The Service to Worker Microarchitecture


In this article, I introduce the most fundamentally important patterns in a Cairngorm application: the
Front Controller, Event Broadcaster, and the Command pattern.
Rich Internet applications have grown in complexity due to the number of features required in the
application. Consider the following features in the Cairngorm Store:
• Get products from database
• Sort products by name or price
• Filter products according to price slider
• Add product to shopping cart
• Remove product from shopping cart
• Check out an order
There are six features, requirements, use cases, or stories, depending on the methodology you follow
for capturing business requirements from a client. For a real-world rich Internet application such as the
Cairngorm Store, the number of these features easily increases from 5–10 requirements to 50–100
different features. The Adobe Consulting group has consulted on and developed applications that have
hundreds to thousands of these features, delivered by teams of 20–30 developers.
As the number of features grows, so too does the scale and complexity of the rich Internet application.
It is in this case that Cairngorm can help you scale and simplify the complexity.

Service to Worker: Mapping User Gestures and System Occurrences to Events


The user executes the vast majority of features through user gestures. Remember that a user gestures
the application through mouse or keyboard; for instance, through clicking a button, double-clicking an
entry in a data grid, dragging and dropping an object, or submitting a form.
Consider the Cairngorm Store features listed previously. All but the request to get products from the
database occur because of a user gesture. Here are some examples of user gestures:
• User sorts products by clicking a button
• User drags a slider component to filter products
• User adds products to the shopping cart by clicking an Add to Cart button or by dragging and
dropping a thumbnail or product image into the shopping cart
More often than not, you map the execution of a feature to a user gesture.
If you come from a web application development world, you will recognize that each feature requires
an HTTP request to the server, with the server doing some of the work on your behalf and returning
data to the client with a browser refresh.
It is not always the case with an RIA that a feature "execute" follows a user gesture; the fetching of the
products from the database is something done immediately when the application starts. Rather than
resulting from a user gesture, getting the products from the database is an event that happens within the
system. Other such system-level events might include a feature that executes periodically, such as
fetching e-mail messages every 30 seconds.
The single biggest innovation is that the Cairngorm framework treats user gestures and system-level
events the same way by mapping them to a Cairngorm event. Breaking free of the request/response
paradigm of HTML-based technologies, user requests are no longer synonymous with HTTP requests.
Instead, user requests are internal events that components can broadcast when they recognize a user
gesture or system event. Rich Internet applications handle user requests without a server round trip.

Service to Worker: Listening for Events with the Front Controller


Consider the events in the Cairngorm Store. The features mentioned previously map to events such as
getProducts, addProductToShoppingCart, deleteProductFromShoppingCart,
filterProducts, sortProducts, and so forth. Whenever a user gesture indicates the desire to
execute a feature, Cairngorm necessitates that you broadcast an appropriate event.
In response to each event, I have mentioned executing a feature. A common design pattern from the
original Gang of Four pattern catalog is an excellent choice in such a scenario. In this pattern, you
implement features as classes, called commands. Each and every command exposes a single entry
point, a method called execute(), which allows a third party to invoke the command without
understanding what the command accomplishes. Often these commands are called worker classes
because they are responsible for actually carrying out the work behind the application.

Understanding Command Classes


Typically within Cairngorm, adding a new feature to the application is considered adding a new
Command class that can accomplish the work associated with the feature.
Consider one of the key features of Cairngorm Store—the ability to add products to a shopping cart. To
implement this feature, you create a new Command class called
AddProductToshoppingCartCommand, the full code of which follows:
AddProductToshoppingCartCommand, the full code of which follows:
import org.nevis.cairngorm.commands.Command;
import org.nevis.cairngorm.control.Event;
import org.nevis.cairngorm.samples.store.model.ModelLocator;
import org.nevis.cairngorm.samples.store.vo.ProductVO;

class org.nevis.cairngorm.samples.store.command.AddProductToShoppingCartCommand
implements Command
{
public function execute( event : Event ):Void
{
var product : ProductVO = ProductVO( event.data.product );
var quantity : Number = Number( event.data.quantity );
ModelLocator.shoppingCart.addElement( product, quantity );
}
}

It's not very complicated, is it? First of all, see how the application-specific Command class
implements the Cairngorm Command interface. If you were to view the source code for Cairngorm,
you would see that this interface simply enforces that the command must have a method called
execute() that can act as its entry point. This allows Cairngorm to execute each and every
command without caring about what the command actually does.
If you look at the implementation of the execute() method, you can see how the event that caused
Cairngorm to execute the command contains a ProductVO value object and a quantity in the data
payload of the Event class. The Event class is also a Cairngorm class that gives each Cairngorm
event a type (such as the addProduct type) and some associated data (such as the product and the
product quantity to add to the shopping cart).
Because the shopping cart is a client-side state, it resides on the ModelLocator class. Therefore, the
command has only to carry out the work that the user requests and add it to the appropriate amount for
the product in the shopping cart, using the methods on the ShoppingCart class.
That's it! There's minimal work required to create a simple feature of the Command class. The
command queries the event, extracting any data associated with the event so that it can perform its task.
If executing the command affects the state of the application—such as requiring a new product to
appear in the Shopping Cart view, for instance—the application accomplishes the task by updating the
client-side state through ModelLocator. If you bind views correctly to ModelLocator, the user
experience will reflect these state changes accordingly.
Creating Helper Classes in Cairngorm
There is a very important design point to emphasize here. In the preceding example, all complex
business logic associated with what a shopping cart can and cannot do is encapsulated in a class called
the ShoppingCart class. If a user adds a product to the cart, for instance, the ShoppingCart class
adds it to the cart if it doesn't exist already. If the product already exists in the cart, the class increases
in quantity.
Cairngorm does not relieve the developer of the responsibility of creating his or her own business
objects and classes on the client. Indeed, what makes an application specific to its business domain is
its classes.
Developers should constantly seek to extract these classes from the Cairngorm architecture, pulling
business logic out of commands and into classes, a classic implementation of Extract class refactoring.
The beauty of this technique is that you can unit-test these classes extensively, document their APIs,
and make them available for reuse to other application developers without any dependency on the
surrounding Cairngorm application.
The ShoppingCart class in Cairngorm Store is an excellent example of this design principle. Apply
it at every opportunity in your own development.

Managing Commands with a Controller


In the real world, having a large collection of workers with no one in charge is a recipe for chaos.
Delegating responsibility to someone to take charge and control the workers from the front ensures that
workers do their duty when they're required to do so.
Borrowing a design pattern from the J2EE community, but implementing it to respond to events on the
client rather than HTTP requests on the server, Cairngorm introduces the Front Controller pattern as a
single point of entry for all Cairngorm events.
Let's take a look at the Front Controller pattern in the Cairngorm Store:
class org.nevis.cairngorm.samples.store.control.ShopController extends
FrontController
{
public function ShopController()
{
initialiseCommands();
}

//----------------------------------------------------------------------------

public function initialiseCommands()


{
addCommand( ShopController.EVENT_GET_PRODUCTS, new GetProductsCommand() );
addCommand( ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART, new
AddProductToShoppingCartCommand() );
addCommand( ShopController.EVENT_DELETE_PRODUCT_FROM_SHOPPING_CART, new
DeleteProductFromShoppingCartCommand() );
addCommand( ShopController.EVENT_FILTER_PRODUCTS, new FilterProductsCommand()
);
addCommand( ShopController.EVENT_SORT_PRODUCTS, new SortProductsCommand() );
addCommand( ShopController.EVENT_VALIDATE_ORDER, new
ValidateOrderCommand() );
addCommand( ShopController.EVENT_VALIDATE_CREDIT_CARD, new
ValidateCreditCardCommand() );
addCommand( ShopController.EVENT_COMPLETE_PURCHASE, new
CompletePurchaseCommand() );
}

//-------------------------------------------------------------------------

public static var EVENT_GET_PRODUCTS = "getProducts";


public static var EVENT_ADD_PRODUCT_TO_SHOPPING_CART =
"addProductToShoppingCart";
public static var EVENT_DELETE_PRODUCT_FROM_SHOPPING_CART =
"deleteProductFromShoppingCart";
public static var EVENT_FILTER_PRODUCTS = "filterProducts";
public static var EVENT_SORT_PRODUCTS = "sortProducts";
public static var EVENT_VALIDATE_ORDER = "validateOrder";
public static var EVENT_VALIDATE_CREDIT_CARD = "validateCreditCard";
public static var EVENT_COMPLETE_PURCHASE = "completePurchase";

First, recognize the best-practice approach of naming all events as constants on the
FrontController instance, ShopController. A common development error is to set up the
controller to listen for an event called addProductToShoppingCart but then, when broadcasting
the event, mistakenly refer to the event as addProduct. Consequently, you think you have broadcast
a valid event and caused a Command class to execute; instead, FrontController refuses to invoke
any commands and does not recognize the event name. However, these errors manifest at runtime only,
as you broadcasting events such as
ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART. The compiler catches any
mistyped events noisily at compile time, rather than failing silently at runtime. While Cairngorm does
not require this, it's a best practice that we highly recommend.
Next, notice how the constructor calls the initialiseCommands() method in the controller,
ensuring that when the application does create the controller, it creates it with the full knowledge of
which commands it can delegate work to, depending on which events it hears being broadcast.
Let's look at the example of adding products to the shopping cart. When the app broadcasts the
ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART command, the following
entry in the controller ensures that the execute() method on the
AddProductToShoppingCartCommand is invoked:
addCommand( ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART,
new AddProductToShoppingCartCommand() );

By extending the base FrontController class in the Cairngorm framework, you can use the
addCommand() method of the FrontController class to register events with corresponding
command classes. The underlying Cairngorm architecture does the rest of the work. It simply
broadcasts the appropriate event from anywhere in your application and Cairngorm ensures that the
relevant command is invoked.
You create your controller in the main entry point for MXML. In the Cairngorm Store, this is in the
Main.mxml file, as follows:
<control:ShopController id="controller" />
The "control" namespace was defined in the Application tag as pointing at the appropriate
Cairngorm package:
xmlns:control="org.nevis.cairngorm.samples.store.control.*"

This is all you need to do to ensure that the application has a Front Controller pattern that responds to
all the events and invokes all the commands that you registered with the addCommand() method.

Service to Worker: Broadcasting Cairngorm Events with the Event Broadcaster


The final piece of the puzzle involves figuring out how to broadcast the events to which the controller
responds.
Cairngorm provides a singleton EventBroadcaster class that collaborates with the
FrontController class. Whenever you want to dispatch Cairngorm events, dispatch them with the
Cairngorm Event Broadcaster.
Take a look at the different ways a user might perform user gestures to add products to a shopping cart.
The user might click the Add to Cart button on the ProductDetails MXML component. If you
look at the code for ProductDetails.mxml, notice that you have a private helper method on the MXML
that broadcasts an addProduct event out of the component to the parent component,
SideArea.mxml:
private function addProduct() : Void
{
var event : Object = new Object();
event.type = "addProduct";
event.product = selectedItem;
event.quantity = quantity;
dispatchEvent( event );
}

Look at the instantiation of ProductDetails in the SideArea component. See the following
code:
private function addProductToShoppingCart( event : Object ) : Void
{
EventBroadcaster.getInstance().broadcastEvent(
ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART, event );
}

This is another best practice we recommend: Providing simple methods that describe the broadcasting
of an event in business terms. In this way the instantiation of the ProductDetails component is as
follows:
<details:ProductDetails
id="productDetailsComp"
width="100%" height="325"
currencyFormatter="{ ModelLocator.currencyFormatter }"
selectedItem="{ ModelLocator.selectedItem }"
addProduct="addProductToShoppingCart( event )" />

Essentially, the ProductDetails component exposes an addProduct event that contains the
product and quantity that the user gesture indicated adding. You take this event and broadcast it to the
FrontController class using the Event Broadcaster as
EVENT_ADD_PRODUCT_TO_SHOPPING_CART. With those few lines of code, you can now entrust
Cairngorm to ensure that AddProductToShoppingCartCommand is invoked, doing all the work
necessary to update the client-side model through ModelLocator, which will also result in the
ShoppingCart view (which binds to the ShoppingCart model in ModelLocator) updating to
show the new state of the shopping cart.
Now you can recognize how the Service to Worker microarchitecture (Front Controller, Event
Broadcaster, and Command patterns) collaborates with the Model Locator and Value Object patterns to
handle an entire conversation between the user and the rich Internet application.

Dragging and Dropping Products into the Shopping Cart


It's trivial to implement a drag-and-drop feature to your application. The ShoppingCart component
(ShoppingCart.mxml) has a drop handler called doDragDrop() that behaves exactly as the button
handler did previously, broadcasting an addProduct event from the ShoppingCart component,
which is handled in the SideArea MXML component, which is identical to the ProductDetails
component:
<cart:ShoppingCart
id="shoppingCartComp"
width="100%" height="100%"
shoppingCart="{ ModelLocator.shoppingCart }"
select="ModelLocator.selectedItem = event.target.selectedItem"
currencyFormatter="{ ModelLocator.currencyFormatter }"
addProduct="addProductToShoppingCart( event );"
deleteProduct="deleteProductFromShoppingCart( event );"
gotoCheckout="ModelLocator.workflowState = ModelLocator.VIEWING_CHECKOUT;" />

All the drag-and-drop "view logic" is encapsulated in the components for the drop source and drop
target. It is of no consequence to Cairngorm how this is implemented. Quite simply, to hook the
operation up to the underlying Cairngorm application, you simply broadcast the
ShopController.EVENT_ADD_PRODUCT_TO_SHOPPING_CART event as a consequence of the
appropriate user gesture. In this case, it is the drag-and-drop operation.

Where to Go from Here


We've flown quite a distance across the terrain of a Cairngorm application now. Regardless of how you
choose to build rich and immersive user experiences using MXML and ActionScript, Cairngorm plays
an important role in listening to the user's interaction with these experiences, in translating these
interactions into an understanding of what the user expects, and in executing work on the user's behalf.
In Cairngorm, you have learned to achieve this goal with a clean collaboration of design patterns: Front
Controller, Event Broadcaster, and Command. These patterns form a tight microarchitecture called
Service to Worker.
Every time you add a feature to the application, you do so by creating a specific Command pattern,
such as AddProductToShoppingCartCommand. This command performs the work associated
with the user gesture or system event that caused the command to execute. For Cairngorm to execute
this command, you use the addCommand() method in FrontController to register each
Command pattern with an appropriate event name. Furthermore, I've advocated a best practice of
naming your events as static constants on your Front Controller pattern so that you can benefit from
compile-time checking of your event broadcasting, rather than silent runtime failure if you mistype
event names.
I've shown you how Cairngorm provides a base class for your Front Controller patterns and an
interface for your Command patterns. If you extend and implement these classes, you can use the Event
Broadcaster pattern from anywhere in your application to translate user gestures or system-level events
into events that cause Cairngorm to pass control to the appropriate Command pattern.
This initial foray into application development may cause you to pause and reflect on the flow of
control between different parts of the application architecture. You will quickly become comfortable
with this flow, however, and you and your team will approach the addition of each and every feature to
a Cairngorm application in the same way. In short, you will add an event to the controller, register it
with a Command class, and implement the Command class to do all the work. As you drive the
development of your application with feature after feature, you will do so in a consistent, predictable
manner that scales well.
No more scattering of business logic across an ever-growing ecosystem of MXML components. No
more monolithic classes that state "if the application just did this, then do that; but if it did this, then do
the next thing..."
The scalability of design, maintainability of the code base, and the simple, consistent approach to
delivering new features into the application bring out the major benefits of using the Cairngorm
microarchitecture.
I've discussed how to implement the view and how to keep state on the view, or the rich in rich Internet
application. I've discussed how to implement features with the addition of business logic encapsulated
in commands, or the application in rich Internet application.
In Part 5, I'll discuss the Internet in rich Internet application. You'll learn how to complement the
richness of the user experience with the ability to reach out and invoke business logic that exists on a
server—whether it's your own application server or third-party services exposed on third-party servers.
This final piece of the puzzle explains everything you need to know to design, architect, and deliver
your own highly complex enterprise rich Internet applications.
Developing Flex RIAs with Cairngorm Microarchitecture – Part 5: Server-Side Integration

Developing Flex RIAs with Cairngorm Microarchitecture – Part


5: Server-Side Integration

Steven Webster
Adobe Consulting
www.richinternetapps.com

Table of Contents
1. Introduction
2. Integrating with Flex RPC Services
3. Locating Services with the Service Locator
4. Proxying Services with the Business Delegate
• Printable version
• Send feedback
• Get an e-mail update of new articles
• Take a survey

Comments
Created:
13 March 2006
User Level:
Intermediate

In Part 4 of this series, you learned about the client-side features of the Cairngorm application. I
advocated some best practices for structuring and architecting your view—the MXML and
ActionScript code that describes your user experience. I then dived into the details of feature-driven
development using the Front Controller, Event Broadcaster, and Command patterns, explaining how
they assist in rapidly and consistently delivering new functionality to the evolving rich Internet
application (RIA) development.
The final piece of the RIA puzzle that Cairngorm helps you solve is integrating your application with
services that reside on "the other side of the wire"—that is, on the server infrastructure. In the same
way that you desire a consistent approach to implementing client-side business logic, you'll benefit
from a consistent means of invoking business logic on a server and fetching data from a server for your
client-side application.
By the end of this article, you will have been fully exposed to the collaboration of design patterns in a
Cairngorm application and will be able to explore and understand the implementation of the other
features of the Cairngorm Store more fully.

Requirements
To complete this tutorial you may want to install the following software and files so that you can follow
along:

Macromedia Flex
• Try
• Buy

Cairngorm version .99


• Download Cairngorm version .99
Prerequisites
Read the previous articles in the series, starting with Developing Flex RIAs with Cairngorm
Microarchitecture – Part 1: Introducing Cairngorm before reading Part 5.

Integrating with Flex RPC Services


One of the challenges when developing a rich Internet application are which tradeoffs to make with
regard to which functionality the application should and could execute on the client, and which
functionality should reside on a server. The decisions may take into account issues such as
performance, scalability, and security or may simply be dictated by the desire to provide a rich user
experience upon an existing investment in server-side infrastructure.
One luxury of a rich Internet application is the seamless means by which server integration now occurs.
With a web application, requests to the server for data typically results in a page refresh for the user.
With an RIA, however, the user is oblivious to either client- or server-side processing. Requests for
data do not interrupt flow of control; data requests are made asynchronously and the application is
notified when these results become available.
There are a number of mechanisms available for integrating an RIA with server-side data. These are
now known as Flex remote procedure call (RPC) services:
• HTTPService: Passes textual data over HTTP. This is often used to fetch RSS feeds, read XML
generated by a server, or simply pass text-based data from server to client.
• WebService: Allows a Flex application to invoke server-side methods using SOAP web
services and handle the results of web service calls. These web services may reside on the server
that has served the rich Internet application or may call third-party web services through a proxy
on the Flex server.
• RemoteObject: Allows a Flex application to directly invoke methods on Java classes residing
on the application server that has served the RIA. Data transfer is in a binary format (AMF)
over HTTP or HTTPS, with the Flex server translating Java and ActionScript objects as they
pass over the wire.
I am not going to explore these different services in any detail, or offer any thoughts on best practices
for client-server integration. There is a significant amount of discussion of these RPC services in the
official Flex documentation, as well as a great deal of discussion as to why you might choose one
method over another in my book, Developing Rich Clients with Macromedia Flex.
Flex provides you with three MXML tags—HTTPService, WebService, and RemoteObject—
all of which do a great amount of heavy lifting for application developers. Using these tags, you can
easily specify a service location (URL, WSDL location, or Java class), invoke methods on that service,
pass data in these method invocations, and receive the results in the future in a result handler.
As your application scales, it is likely that the number of services you wish to call will increase. It is
also likely that you'll call a mixture of HTTP services, web services, and methods on Java classes.
Likewise, it is also likely that different developers will have different uses for many of the same
services. To solve this recurring challenge in Flex application development, the Cairngorm framework
offers a pair of design patterns—once again borrowed from the J2EE community—to introduce some
consistency where services are declared, how they are invoked, and how their results are handled
within your RIA.
Locating Services with the Service Locator
Often, one challenge large development teams often face is when all team members build against the
same server-side infrastructure. For example, a developer who develops a component realizes he needs
to make a call to a Java class, and deep within the bowels of his component, places a RemoteObject
tag pointing at the Java class. Meanwhile, three other developers on the team do exactly the same thing,
resulting in spaghetti code sprinkled with identical RemoteObject tags.
The Service Locator addresses this purpose; it is a repository of all services that the RIA requires;
within it, you can centralize and reuse your service tags.
Furthermore, by using Service Locator, you abstract developers from whether a service is a Java object,
a web service, or an HTTP service, and allow them to "treat them all the same." In essence, the Service
Locator encapsulates the implementation details of services, leaving application developers simply to
request a service from the Service Locator, invoke methods on the service, and handle the results
however they might be shipped over the wire.
Cairngorm provides a base-class, ServiceLocator, which is a singleton for service access. In a
Cairngorm application, you typically extend this base-class through MXML, with the convention of
always having a file called Services.mxml in the business/package of your application.
Let's take a look at Services.mxml for Cairngorm Store:
<cairngorm:ServiceLocator
xmlns:mx="http://www.macromedia.com/2003/mxml"
xmlns:cairngorm="http://www.iterationtwo.com/cairngorm">

<mx:RemoteObject
id="productService" named="productServiceImpl"
protocol="http"
showBusyCursor="true"
result="event.call.resultHandler( event );"
fault="event.call.faultHandler( event );">
</mx:RemoteObject>

<mx:RemoteObject
id="creditCardService" named="creditCardServiceImpl"
protocol="http"
showBusyCursor="true"
result="event.call.resultHandler( event );"
fault="event.call.faultHandler( event );">
</mx:RemoteObject>

</cairngorm:ServiceLocator>

As you can see here, there are two services: one called productService that you use to fetch
products from the server-side database, and the other called creditCardService that you use to
validate credit card information on the server before approving orders.
Both services are implemented as named services. This means that the information about the actual
Java class is held in the flex-config.xml descriptor file on the server; it is not exposed in any client-side
code. This is a security best practice. It's best not to reveal things like class names that might give a
determined hacker who decompiles the Flex RIA some hints as to the implementation of your server-
side code.
When declaring services in Flex, always specify result and fault handlers. The result handler is the
method called when a service call returns some data; likewise, the fault handler is called when a service
call fails.
Because the Service Locator anticipates that its services will be used multiple times in a multitude of
different ways, it makes no assumptions about how to handle any results that are returned. Instead, the
Service Locator assumes that the result handler and the fault handler will belong to the class called the
service. It achieves this by specifying event.call.resultHandler and
event.call.faultHandler as the handlers through a Flex object know as the pending call.
I won't dive into the details of pending calls in this article because one of the purposes of the Service
Locator is to abdicate the developer from any responsibility of understanding implementation details of
services such as the PendingCall object.
Needless to say, when you specify services, do so by declaring them in a Services.mxml file using the
appropriate MXML service tag—and always specify the result and fault handlers as follows:
result="event.call.resultHandler( event );"
fault="event.call.faultHandler( event );"

Invoking Services on the Service Locator


Having declared services to reside on the Service Locator, you will obviously want to invoke these
services at some point in time.
In Cairngorm Store, let's say you want to fetch all products from the server-side database when the
application starts. When the application starts, it executes the GetProductsCommand command; if
you recall, you use the creationComplete event on the main Application tag to fire a
ShopController.EVENT_GET_PRODUCTS event, which ensures that the application executes the
Command class.
In the Service Locator, productService is a Java class that has a method called
getProducts(). Calling the getProducts() method returns an array list of ProductVO value
objects, which represents all the products that the middleware has pulled out of the underlying
database.
In the entry-point for Cairngorm Store, Main.mxml, you instantiate your Service Locator as follows:
<business:Services id="services" />

Where the business namespace is declared and specifies the package in which Services.mxml resides:
org.nevis.cairngorm.samples.store.business.
Having declared your Service Locator, you could then place the following code into your
GetProductsCommand command if you so desired:
class org.nevis.cairngorm.samples.store.command.GetProductsCommand implements
Command
{

public function execute( event : Event ):Void


{
var service = ServiceLocator.getInstance().getService( "productService" );
service.getProducts();
}
}

In this code, you can see how you use the Service Locator to fetch a service by name and then invoke
methods on the service. The code shows that there is no requirement for developers to know whether
this is a WebService, RemoteObject, or HTTPService RPC service; they simply ask for the service
from the Service Locator and then invoke methods on it.
Now you could refine this code further, so that it specifies the result handler on the Command class as a
method belonging to GetProductsCommand. This would allow the Command class to invoke the
service and handle the result in the context of the Command class.
However, while this would be a more than acceptable solution, there is a final layer of abstraction that
we have found very useful. We recommend it as a starting point for any Cairngorm application.
Let's take a look at the final pattern that Cairngorm advocates: the Business Delegate.
Page 3 of 4
Previous Page
Next Page

Comments (1)
• Anirudh Sasikumar(April 24, 2008)
Tip for Flex 2 and 3 developers:

event.call.resultHandler and event.call.faultHandler should be changed to


event.token.resultHandler and event.token.faultHandler respectively.
• You need to sign in in order to post a comment.
Add Comment

Proxying Services with the Business Delegate


More often than not, a particular service call, such as getProducts(), can be called several times in
several different places in the application. Furthermore, the results from these service calls may be used
differently, depending upon the context in which the service call was made.
For instance, consider a service call that fetches the day's trading values for a particular stock. One
command might render all these data points on a graph, another command might calculate the day's
high and low values for the stock, while still another command class might displays the current value of
the stock only. In this scenario, you might use three different services calls to
service.getStockInformation( "ADBE" ) in these different contexts.
This motivates us to consider how to delegate all the responsibility for business logic that must locate a
service and then invoke a method on the service into a separate class. We call that class a Business
Delegate.
In Cairngorm Store, there are two Business Delegates, one for each of our services. These kind of
design decisions—about how many delegates to have—are entirely up to the individual developer.
Let's look at the implementation of ProductDelegate.as:
class org.nevis.cairngorm.samples.store.business.ProductDelegate
{
public function ProductDelegate( responder : Responder )
{
this.service = ServiceLocator.getInstance().getService( "productService" );
this.responder = responder;
}

//---------------------------------------------------------------

public function getProducts() : Void


{
var call = service.getProducts();
call.resultHandler = Delegate.create( responder, responder.onResult );
call.faultHandler = Delegate.create( responder, responder.onFault );
}

//---------------------------------------------------------------
private var responder : Responder;
private var service : Object;
}

A discussion of the Business Delegate makes the most sense in the context of a Command class that
calls the delegate; in the case above, the GetProductsCommand class:
class org.nevis.cairngorm.samples.store.command.GetProductsCommand implements
Command, Responder
{
public function execute( event : Event ):Void
{
var productsNotLoaded = ( ModelLocator.products == null );
if( productsNotLoaded )
{
var delegate : ProductDelegate = new ProductDelegate( this );
delegate.getProducts();
}
else
{
// products already loaded, so no need to load them again
return;
}
}

//----------------------------------------------------------------------------

public function onResult( event : Object ) : Void


{
var products : Array = event.result;

ModelLocator.selectedItem = products[ 0 ];
ModelLocator.products = products;
ModelLocator.workflowState = ModelLocator.VIEWING_PRODUCTS_IN_THUMBNAILS;
}

//----------------------------------------------------------------------------
public function onFault( event : Object ) : Void
{
mx.core.Application.alert( "Products could not be retrieved!" );
}
}

Let's explore the interaction of these two classes in greater detail. The Command class creates a new
instance of the Product Delegate pattern, passing itself ("this") to the constructor of the delegate.
This is the Command class' way of saying "I want to handle the results of any calls made by the
delegate"—something the delegate calls the "responder" (the object wishing to respond to any results).
By electing to act as a responder, the Command class implements the Responder interface in
Cairngorm; this ensures that the developer adds an onResult() method to handle any delegate
results and an onFault() method to handle any delegate faults.
If you then look at the implementation of getProducts() on the Product Delegate, there are two
lines of boilerplate code that you can add for each and every delegate method:
public function getProducts() : Void
{
var call = service.getProducts();
call.resultHandler = Delegate.create( responder,
responder.onResult );
call.faultHandler = Delegate.create( responder,
responder.onFault );
}

Don't worry too much about the details of this incantation. These lines ensure that the results and faults
from the server are routed back to the responder—in this case, to the the Command class.
With this collaboration of classes in place, the flow of control is both simple and elegant:
• Command class creates a business delegate
• Command class calls business methods, such as getProducts(), on the delegate
• Delegate worries about looking up the service and invoking the service
• At some point in the future, the server returns results to the delegate
• Delegate immediately passes these results to the onResult() method on the command
If you look at the onResult() method of GetProductsCommand, it extracts the array of products
from the event representing the server results and stores them on the ModelLocator, while also
setting selectedItem on the ModelLocator to the first product in the catalogue.
If any other commands have utility for a getProducts() command, they can also call the Business
Delegate method. On large development teams, developers learn to check the delegates to see if any
other developers have implemented methods that they can reuse before invoking the services
themselves.
Incidentally, the server-side implementation of getProducts() is a Java class that employs a data
access object (DAO) to query a relational database (either MySQL or HSQLDB are supported) using
JDBC. Sound complicated? Well, it doesn't matter; that's the entire point of the Business Delegate: to
hide the complexity of server-side implementation from client-side developers. The source is there if
you care.
Stubbing the Business Delegate
There's another great reason for using a Business Delegate pattern. Often, there is one set of developers
responsible for the server-side development of an RIA and another team working on the Flex client.
The Business Delegate class becomes an agreed "contract" between both teams, as the single point of
interface between client and server.
We have often consulted on projects where development has started with a Business Delegate that
doesn't actually call any server-side services. Instead, the Business Delegate is a "stub" class: It creates
mock value objects in ActionScript and directly calls the onResult() method on the calling
command.
Client-side developers can then call the Business Delegate, oblivious to the fact that the data returned
to them is dummy data. Once server-side development is in sync with client-side development, you can
change the method calls on the Business Delegate to call all the way through to the server, with no
further changes required in the Command classes, or in any of the MXML or ActionScript view code.
When working with Cairngorm, many developers wonder about the utility of the Business Delegate
and whether their commands might not just as easily call services using the Service Locator. While it is
certainly our experience and preference to have Command classes oblivious to the concept of server-
side services by employing the business delegate as a proxy, the flexibility of Cairngorm means that
developers can choose not to have Business Delegates if they so prefer.
However, we find that the minimal amount of effort necessary to create these delegates—coupled with
the fact that we usually find ourselves refactoring towards a Business Delegate anyway—to be sound
reasons for including the Business Delegate pattern in all applications that we architect upon
Cairngorm.

Where to Go from Here


You have now been exposed to all of the design patterns that contribute and collaborate in the
Cairngorm microarchitecture.
You've taken a brief tour of Flex RPC services and uncovered the Service Locator patterns as a useful
means of encapsulating all the different services that your rich Internet application might make under a
common class in a predictable location.
As legitimate as it may be to invoke these services from the various Command classes in your
architecture (you are still free to do so if you so wish) the Cairngorm team has found that there are
repeatable benefits to moving all service invocations into a class, one that you delegate all business
logic calls to on the server: the Business Delegate.
As well as recognizing the consistency, scalability, modularity, and reuse that the Business Delegate
pattern can offer, I discussed strategies for development whereby the Business Delegate becomes a
clear contract and "point of integration" between server and client-side development teams.
Finally, I revisited the Command pattern and extended your knowledge of writing commands to include
commands that implement the Cairngorm Responder interface. These commands not only use the
Business Delegate pattern to invoke services, but they advertise through their Responder interface that
they wish to assume the responsibility for handling any results that the Business Delegate receives in
proxying service requests on their behalf.
Make sure that you understand the different Flex RPC services available to you and how to write your
own Service Locator classes. Make sure you understand how to write your own Business Delegates—
by accepting a Responder class in the constructor, liaising with the Service Locator, and adding the
necessary incantations to the pending call of each service request to make sure that results are routed
back to the Responder.
Finally, I explained the additional methods that you can add to commands that implement the
Responder interface to allow commands to take any service call results and update the client-side state,
through the Model Locator design pattern, as the final clause in any conversation between the user and
the RIA.
In Part 6, the final article in this series, I will summarize and reinforce the Cairngorm architecture.
What may have appeared first as complex is actually easy to apply. You'll be able to follow the rapid
addition of a completely new feature to the Cairngorm Store, safe in the knowledge that the way you do
it adheres to the same best practice that thousands of Flex developers worldwide would also follow
when faced with the same code base.
Developing Flex RIAs with Cairngorm Microarchitecture – Part 6: Rapid and Consistent Development
with Cairngorm and Flex

Developing Flex RIAs with Cairngorm Microarchitecture – Part


6: Rapid and Consistent Development with Cairngorm and Flex

Steven Webster
Adobe Consulting
www.richinternetapps.com

Table of Contents
1. Introduction
2. Cairngorm Architecture Review
3. Cairngorm Flow of Control
4. Cairngorm Store Wish List
5. In Perspective
• Printable version
• Send feedback
• Get an e-mail update of new articles
• Take a survey

Comments
Created:
27 March 2006
User Level:
Intermediate
In the final article of this series, let's take a moment to stand on the summit of Cairngorm and look
down at how far we have climbed.
Having acquired some development experience over the last series of articles, you now have the
knowledge, tools, and expertise to be able to scale any complex rich Internet application, applying the
lessons you have learned to tackle any application development project safely and securely, no matter
how steep the problem may first appear.
By applying these lessons, you can consistently, effectively, and rapidly accomplish the design,
development, and delivery of rich Internet applications with the confidence that the methods you use
have been proven effective on numerous challenges as complex and critical as your own.
Let's consolidate this understanding with a quick review of the different patterns in Cairngorm and how
they work together. Recall the essential infrastructure that you must put in place so that you can move
towards your goal by delivering feature after feature into your application.
Finally, let's set ourselves a development task in the Cairngorm Store—and use the exercise to confirm
that you are now ready to develop your own applications with Cairngorm by correctly applying the
same best practices that so many other Flex developers use with success.

Requirements
To complete this tutorial you may want to install the following software and files so that you can follow
along:

Macromedia Flex
• Try
• Buy

Cairngorm version .99


• Download Cairngorm version .99

Prerequisites
Read the previous articles in the series, starting with Developing Flex RIAs with Cairngorm
Microarchitecture – Part 1: Introducing Cairngorm before reading Part 6.

Cairngorm Architecture Review


Let's jump straight in with an end-to-end review of the Cairngorm architecture. The metaphor by which
you can refer to the architecture is that Cairngorm simply establishes a rapport between man and
machine, listening to what the user wants, ensuring that the user gets what he or she wants, and then
communicating that back to the user.
Front Controller Listens for User Gestures
The user is in charge of the conversation. Your rich Internet application awaits some indication from
the user as to what to do. These indications—pressing buttons, dragging and dropping icons, double-
clicking rows or submitting forms—are all called "user gestures."
Cairngorm translates these user gestures into Cairngorm events. Whenever there is a click, press, drag,
drop, or submission of any event that represents a user demand, you use EventBroadcaster to
broadcast an event. The event broadcast is the beginning of the Cairngorm conversation.
The Front Controller pattern is the sole listener to Cairngorm events. By centralizing the handling of
events, the Front Controller assumes responsibility for meeting the user's demands.
However, the Front Controller doesn't do the work; it's a manager, not a worker. The Front Controller
instead maintains a list of "who does what," a list of commands that are best suited to responding to
particular events.

Commands Do All the Work


Once the Front Controller recognizes an event for which it has a command on the payroll, as it were, it
tells that command to execute. The Front Controller tells each and every command what to do in a
consistent manner: the Front Controller calls the execute() method on the command and the
command does its specific work.

Delegate Server-Side Business Logic to Business Delegates


Every so often, the command requires the server to perform a duty. In a rich Internet application, some
business logic executes on the client side. More often than not, however, you'll want to shift some of
the responsibility for business logic to the server.
Commands don't care about how something gets done; they just care that it gets done. Commands
prefer to delegate the responsibility for server-side business logic to another class. There is a good
chance, after all, that several commands that are trying to achieve distinct tasks of their own will all
require the same service for different things. What's more, for all the command knows, the business
logic hasn't even been written on the server yet. Maybe the command is simply calling a dummy
Business Delegate class, where the server-side infrastructure does not yet exist, but the Business
Delegate offers an interface that will exist in the future.
So whenever you have business logic, put it into a Business Delegate class so that your commands can
invoke methods on it.

Business Delegate Finds Services with the Service Locator


The Business Delegate provides a seamless interface between commands and any services on the
server. These services may be Java services, ColdFusion components, web services, or simple HTTP
services. The Business Delegate treats these imposters just the same, invoking them when the
command asks and handing results to the command immediately when they become available.
However, the detailed implementation of these services—the names of the Java classes or CFCs,
whether they are named or unnamed services, the location of WSDL files or the URLs for HTTP
services—are all encapsulated into one single repository of services, called the Service Locator.
The Service Locator is a single directory of all services that your rich Internet application requires.
Because only the Business Delegate has responsibility for calling services, only the Business Delegate
uses the Service Locator to locate services by name (caring nothing of their implementation) before
invoking these services and handing the results to the Command classes.
Remember, any Command classes that assume the reponsibility of responding to service calls and
taking the returned data from the Business Delegate must do so by implementing the Responder
interface. In this way, the Business Delegate knows that the command will have an onResult()
method to handle all results and an onFault() method to handle any errors.

Transfer Data as Value Objects


What happens to the data that is passed between client and server, and held on the client? Cairngorm
insists that you treat data with a little respect, encapsulating it in Value Objects that describe what the
data is in business terms ("it's an Order") rather than in technical terms ("it's an ArrayList of Objects
containing a String and a Number").

Store State in the Model Locator and Let Model Notify View
Finally, your application must be able to communicate back to the user. In Cairngorm, the Model
Locator is a single place that holds the entire application state. Though we care little about how the user
experience is implemented with MXML and ActionScript, we do insist that anywhere the view is
dynamic that the data for this view uses data binding to the Model Locator.
The Model Locator contains only Value Objects. When your Command classes ask the Business
Delegate to call some server-side business logic on your user's behalf, they implement the Responder
interface and receive either Value Objects or collections of Value Objects in the onResult() method.
The very last part of the converstation in a Cairngorm application results in the command updating the
Model Locator with any new state represented by these Value Objects. With the Model Locator using
data binding to notify the view, the user interface updates to display any new data and completes the
conversation with the user.

Cairngorm Flow of Control


What I have verbosely described above is the flow of control through the various design patterns in a
Cairngorm architecture. Each and every feature in an application traces the same flow of execution,
with user gestures becoming events, events becoming service calls, and data passing back into the
model.

Adding a New Feature to a Cairngorm Application


When you add a new feature to a Cairngorm application, it is as simple as the following process:
1. Register an event and command with the Front Controller using addCommand().
2. Implement a new command as follows:
a. Implement the execute() method to do the work.
3. Implement the onResult() method to handle any results from the server:
i. Any results are used to update the Model Locator.
4. The Model Locator automatically updates the view.
5. Add any new service calls that the Command requires for the Business Delegate.
6. If these service calls require new services, add them to the Service Locator.
Additionally, you will have to create any Value Objects that are required to pass data between the
Command and Business Delegate, between the Business Delegate and the server, or to store data on the
Model Locator. Typically, however, your Value Objects will exist early in the development of your
application and you will consistently reuse them as you add new features to your application.
Similarly, as your application grows, the server-side services very quickly become locked in place and
application development proceeds even more quickly, as follows:
1. Register an event and command with the Front Controller using addCommand().
2. Implement a new command.
That's really all there is to it.

Debugging a Cairngorm Application


Furthermore, debugging a Cairngorm application follows the same predictable steps. If a desired
feature doesn't perform in response to a user gesture, the debug cycle is always the same:
1. Check whether the event is registered with the Front Controller.
2. Check whether the execute() method is called on the command by the Controller.
3. Check that the appropriate delegate methods are called.
4. Check that the onResult() method is called in the command.
5. Check that the model is updated in the Model Locator.
With these five steps, it's painless to isolate a problem in an application and fix it.

Cairngorm Store Wish List


One feature often found in e-commerce applications is a "wish list," a temporary list of products that
the user might want to purchase in the future without adding them to the shopping cart.
In an agile development team, the requirement or "story" for a Wish List in Cairngorm Store might read
as follows:

Cairngorm Store Wish List


In addition to being able to add items from the store into their Shopping Basket, a customers could use
a Wish List feature to track items that they wish to purchase in the future.
Using a tab-interface, the customer will be able to choose either a Shopping Basket or a Wish List as
the place where they place items. Items placed in the Wish List do not appear in the checkout when the
customer proceeds to purchase the items in their shopping basket.
The customer will be able to add items to their Wish List either by dragging a product's image or
description from a product list onto the Wish List, by dragging the image from the product details panel
onto the Wish List, or by pressing an Add to Wish List button from the product details panel.

Note that this requirement doesn't dictate how the customer might move objects between the Wish List
and the checkout. Let's assume for now that this requirement is an additional story.
Before the user experience gods strike us down, it's worth also noting that the choice of a tabbed
interface is a functional one as implemented by a J2EE developer for the purposes of this
demonstration. In a real-world project, I would use the capabilities of a user experience consultant to
incorporate the Wish List seamlessly and effectively into the overall information architecture!
As is typical in an agile development, a developer usually breaks a story down into tasks. With a
Cairngorm microarchitecture in place, the tasks on any given feature become quite predictable and
repeatable. You may remember I discussed feature-driven development in Part 4 of this article series.
For the Wish List story above, I suggest the tasks in the story are as follows:
For the Wish List story above, I suggest the tasks in the story are as follows:
• Register a new addProductToWishList event with the Front Controller class.
• Create a new AddProductToWishList command to handle the event.
• Create a WishList object that resides within ModelLocator.
• Implement the View:
• Add the WishList object into a Tab Navigator control next to the Shopping Card.
• Dynamically bind the WishList object to ModelLocator.
• Broadcast user gestures to FrontController when the user presses the Add to Wish List
button.
• Broadcast user gestures to FrontController when the user drags and drops into the
WishList object.
Let's follow the code associated with each of these tasks!

Register Event with the Front Controller Class


The very first step is to indicate to the Cairngorm-based application that there is a new user gesture that
might occur related to the user, who wants to add products to their wish list.
The Cairngorm Store has it's own Front Controller instance, ShopController.as, which you use to
register all the appropriate Cairngorm Store commands.
First, you must add the name of the new event to the ShopController as follows:
public static var EVENT_ADD_PRODUCT_TO_WISH_LIST = "addProductToWishList";

Remember, by using a static constant to name our events, you introduce compile-time checking that the
events broadcasted are valid ones. This ensures that your application does not fail silently when you
inadvertantly spell the name of the event incorrectly before broadcasting it into a black-hole!
Next, you must register a Command class that will assume responsibility for carrying out the work
associated with this event. Do this by adding a new entry to the initialiseCommands() method
as follows:
addCommand( ShopController.EVENT_ADD_PRODUCT_TO_WISH_LIST, new
AddProductToWishListCommand() );

That's it as far as the Front Controller class instance is concerned. Now it knows of the new event, and
it knows what to do when the event occurs.
So next, you have to create the Command class that you have delegated as responsible for this event:
the AddProductToWishList Command class.

Creating the AddProductToWishListCommand Command Class


Let's just look at the code for the new command class, as it is so simple and self-explanatory:
import org.nevis.cairngorm.commands.Command;
import org.nevis.cairngorm.control.Event;
import org.nevis.cairngorm.samples.store.model.ModelLocator;
import org.nevis.cairngorm.samples.store.vo.ProductVO;

class org.nevis.cairngorm.samples.store.command.AddProductToWishListCommand
implements Command
{
public function execute( event : Event ):Void
{
var product : ProductVO = ProductVO( event.data.product );
var quantity : Number = Number( event.data.quantity );
ModelLocator.wishList.addElement( product, quantity );
}
}

There's nothing complex at all about this code ... the execute() method is the command-
independent entry point that the Front Controller calls whenever a
ShopController.EVENT_ADD_PRODUCT_TO_WISH_LIST occurs.
The execute() method simply adds the appropriate number of the product involved in the user's
request to "add to wish list" to the WishList object held on ModelLocator.
And again, that's it. You can assume for now that the user interface, the view, are bound through Flex
data-binding to the WishList object held on ModelLocator. That's all there is to do in terms of
business logic!
The next step is to ensure that we have a WishList object on ModelLocator.

Store the WishList Object in ModelLocator


Cairngorm makes Flex development embarassingly simple from this point forward. Since you already
have a ShoppingCart class in Cairngorm Store that maintains a list of products and quanties of
those products, there is absolutely no reason you cannot simply reuse this class to implement the
WishList object. A WishList object is after all, simply a Shopping Cart that you don't necessarily
want to take to the checkout on this particular visit.
So here's the code you add to ModelLocator.as:
Quite simply, you create a new instance of the ShoppingCart class and call it wishList
instance. You create the new instance in ModelLocator's constructor, as follows:
ModelLocator.wishList = new ShoppingCart();

This assumes that you have declared the wishList instance alongside the other definitions in
ModelLocator, like so:
public static var wishList : ShoppingCart;
That's really all there is to it. Are you getting a sense of just how rapidly you can add new features to a
Cairngorm application?

Implement the View


So we have a Command class created, it's registered with the Front Controller class, it updates the
Model Locator class with products added to the wishlist, and you've reused a business object
(ShoppingCart) to implement our the wish list.
All that remains is creating the user interface for the wish list to ensure that it's dynamically bound to
ModelLocator for the presentation of dynamic data, and to ensure that any user gestures that occur
on the interface result in our ShopController.EVENT_ADD_PRODUCT_TO_WISH_LIST being
broadcast.

Adding the Wish List to the View


I'm going to replace the area of screen that only shows the ShoppingCart MXML component with a Tab
Navigator that contains two instances of the ShoppingCart MXML component. The first of these
instances is our original shopping cart, while the second will be the wish list.
You'll alter the ProductDetails component to capture when the user has gestured to add a product
to the wish list, as well as adding a product to the shopping cart. This will require that the
ProductDetails MXML component now have an addProductToWishList event to which you can
hook code, as shown in the highlighted code below.
This simply requires us altering SideArea.mxml as follows:
<details:ProductDetails
id="productDetailsComp"
width="100%" height="325"
currencyFormatter="{ ModelLocator.currencyFormatter }"
selectedItem="{ ModelLocator.selectedItem }"
addProduct="addProductToShoppingCart( event )"
addProductToWishList="addProductToWishList( event )" />

<mx:TabNavigator width="100%" height="100%">

<!-- the Shopping Cart -->


<cart:ShoppingCart
id="shoppingCartComp"
label="Shopping Cart"
width="100%" height="100%"
shoppingCart="{ ModelLocator.shoppingCart }"
selectedItem="{ ModelLocator.selectedItem }"
select="ModelLocator.selectedItem = event.target.selectedItem"
currencyFormatter="{ ModelLocator.currencyFormatter }"
addProduct="addProductToShoppingCart( event );"
deleteProduct="deleteProductFromShoppingCart( event );"
gotoCheckout="ModelLocator.workflowState =
ModelLocator.VIEWING_CHECKOUT;" />

<!-- the Wish List -->


<cart:ShoppingCart
id="wishListCartComp"
label="Wish List"
width="100%" height="100%"
shoppingCart="{ ModelLocator.wishList }"
selectedItem="{ ModelLocator.selectedItem }"
select="ModelLocator.selectedItem = event.target.selectedItem"
currencyFormatter="{ ModelLocator.currencyFormatter }"
addProduct="addProductToWishList( event );"
deleteProduct="deleteProductFromShoppingCart( event );"
gotoCheckout="ModelLocator.workflowState =
ModelLocator.VIEWING_CHECKOUT;" />

</mx:TabNavigator>

Start by looking at the ShoppingCart instance called wishListCartComp in the Tab Navigator
control.
First of all, since the wishListCartComp instance data binds to ModelLocator.wishList,
then any changes to the wish list model are automatically taken care of by the internals of the Shopping
Cart component. That's a tremendous example of component reuse in action!
The addProduct event handler invokes a method, addProductToWishList(), which you need
to define in script in the SideArea.mxml page, as follows:
private function addProductToWishList( event : Object ) : Void
{
EventBroadcaster.getInstance().broadcastEvent(
ShopController.EVENT_ADD_PRODUCT_TO_WISH_LIST, event );
}

This method is repsonsible for translating the user gesture into the appropriate Cairngorm event; now,
when the user either drops a product into the wishListCartComp instance of the shopping cart
component, it is recognised as a user gesture to add something to the Wish List, and this gesture is
translated into the appropriate Cairngorm event.
We re use this addProductToWishList() method in our ProductDetails MXML component, as
shown in this line of code:
addProductToWishList="addProductToWishList( event )"

Clearly, this requires that the ProductDetails MXML component can broadcast out an
addProductToWishList event as the result of a click event happening on a new button "Add to
Wish List" that is placed inside it. So the final piece of view code required is in the following additions
to ProductDetails.mxml.
First, update the definition of MetaData on ProductDetails to advertise the new event you can
broadcast, as shown by the additional highlighted line of code below:
<mx:Metadata>
[Event("addProduct")]
[Event("addProductToWishList")]
</mx:Metadata>

Finally, declare the new button and mutate its click event into a more meaningful business event,
addProductToWishList. Declare a utility method that broadcasts the
addProductToWishList event with some some additional information: the product to be added
(the currently selected item) and the quantity of that product the user has indicated he or she wishes to
add:
private function addProductToWishList() : Void
{
var event : Object = new Object();
event.type = "addProductToWishList";
event.product = selectedItem;
event.quantity = quantity;
dispatchEvent( event );
}

You can then add a new button next to the "Add To Shopping Cart" button, to instead add to the wish
list, as shown in the highlighted code below:
<mx:Button label="Add to Cart" click="addProduct();" />
<mx:Button label="Add to WishList" click="addProductToWishList();" />

This demonstrates one of the best practices we highlighted in the third article in the series: taking a
click event on a button, turning it into a more meaningful event that represents our business domain
("addProductToWishList"), and loosely coupling the MXML components—in this case ProductDetails
and SideArea MXML components through the broadcasting and handling of these events.
And that's it. Now you've added all the code to the MXML that represents the the user experience for
the wish list. By dynamically binding this MXML to the Model Locator class and by translating user
gestures into Cairngorm events, the view is tied into the fabric of the underlying Cairngorm
architecture.

In Perspective
I hope that this final article has sealed a journey of understanding and reinforced the benefits of
building rich Internet applications on the Cairngorm microarchitecture. The benefits demonstrate
themselves very quickly as the application scales in terms of the number of features in the product you
are developing.
Furthermore, I would trust that you now recognise the predictability and consistency in how a
Cairngorm-aware developer chooses to decompose a business requirement into technical tasks that can
be implemented upon the Cairngorm microarchitecture. It is my experience that such consistency and
predictabilty yields so many benefits over and above elegance of code.
On Cairngorm-based projects, it is my finding that developers are able to more accurately and
consistently estimate the cost and effort involved in implementing a particular feature by decomposing
into consistent tasks, and having many previous yardsticks against which to measure.
It is my experience that with a Cairngorm microarchitecture, developers are much more able to
embrace the concept of a "collective ownership," where a developer is no longer a specialist in one
specific area of the application, but is instead a generalist that able to implement feature across the
breadth of an application. Aside from addressing the "what if one of your developers is knocked over
by a bus" dilemma, Adobe Consulting has found that generalization means that the skill level of a team
develops at a much greater rate than if developers become specialists in only a small subset of the
product and the technology platform.
There are many many other benefits to gain from an engineering perspective, but if you are with me
this far, I trust you are already realizing the benefits for yourself. Most importantly, I trust that you have
recognized that standing on the summit of Cairngorm, it's not actually very far down to the bottom.
It's important to qualify that Cairngorm isn't the only way to build rich Internet applications. It is,
however, a proven way of delivering rich Internet applications into production. From that perspective,
it exemplifies best practices from the perspective of the numerous organizations, teams, and individuals
who are working with Flex and Cairngorm together.
If you choose to embrace Cairngorm, or even just the concepts and ideas we have presented through
Cairngorm into your own rich Internet application development, then I am confident your delivery will
be all the more assured because of it.
I look forward to seeing your great work become even greater user experiences.

Where to Go from Here


Cairngorm continues to evolve with the Flex platform.
We will be releasing Cairngorm 2.0 to accompany the release of Flex 2.0. In the meantime, there is a
beta release of Cairngorm 2.0 that is tracking the beta cycle of Flex 2.0, that you can get at
www.richinternetapps.com/archives/000143.html.
Adobe Consulting is committed to continuing to invest in the support of the Cairngorm platform,
blending real-world field experience with the Flex product engineers and community members who are
actively engaged in the Cairngorm committee.
The active members of the Cairngorm committee are all regular contributers to the Flexcoders mailing
list, where you can ask any of your Flex and Cairngorm-related questions.
For those interested in how Cairngorm has been implemented, see the book Developing Rich Clients
with Macromedia Flex by Steven Webster and Alistair McLeod, which covers many of the concepts
behind Cairngorm in significant detail.

You might also like