Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Creative tools for business
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Flex Developer Center /

Developing Flex RIAs with Cairngorm microarchitecture - Part 5: Server-side integration

by Steven Webster

Steven Webster
  • Adobe Consulting
  • www.richinternetapps.com

by Leon Tanner

Leon Tanner
  • Adobe Consulting

Content

  • Integrating with Flex RPC services
  • Locating services with the Service Locator
  • Proxying Services with the Business Delegate

Modified

21 July 2008

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
Flex

Requirements

Prerequisite knowledge

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

User level

Beginning

Required products

  • Flex Builder 3 (Download trial)

Additional Requirements

Cairngorm version 2.2

  • Download Cairngorm version 2.2

Cairngorm Store

Throughout the series you will find references to code taken from an e-commerce application named Cairngorm Store. You may use this sample application to gain a better understanding of Cairngorm, but please consider it only as a guide. Adobe is not responsible for maintaining the Cairngorm Store application.

  • Download Cairngorm Store (J2EE Container version)
  • Download Cairngorm Store (non J2EE Container version)

In Part 4 of this series, we discussed the client-side features of the Cairngorm application and advocated some best practices for structuring and architecting your view, that is, the MXML and ActionScript code that describes your user experience. We 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 rich Internet applications (RIAs).

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. You've seen the benefits of adopting a consistent approach to implementing client-side business logic, and this article will demonstrate the benefits of a consistent approach to 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 seen the entire set of Cairngorm design patterns and how they collaborate in a Cairngorm application.

  • Part 1: Introducing Cairngorm
  • Part 2: Keeping state on the client
  • Part 3: Architecting the view
  • Part 4: Feature-driven development
  • Part 5: Server-side integration
  • Part 6: Rapid and consistent development with Cairngorm and Flex

Integrating with Flex RPC services

When developing a rich Internet application, one challenge is deciding which functionality the application can and should execute on the client, and which functionality should reside on a server. In evaluating these tradeoffs, you might take into account issues such as performance, scalability, and security. In other cases the decision may simply be dictated by the desire to provide a rich user experience based on an existing investment in server-side infrastructure.

One luxury of rich Internet application development is the seamless means by which server integration now occurs. With a web application, a request to the server for data typically results in a page refresh for the user. With an RIA, however, the user is oblivious to the distinction between client-side and server-side processing. Requests for data do not interrupt the flow of control; instead, data requests are made asynchronously and the application is notified when these results become available.

There are a number of mechanisms available for integrating a Flex RIA with server-side data. Flex data access components use remote procedure calls (RPCs) to interact with server environments. There are three Flex data access components:

  • 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 web services using SOAP 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 server.
  • RemoteObject: Allows a Flex application to directly invoke methods on Java classes residing on the application server that has served the RIA. Data is transferred in binary format (Adobe Action Message Format or AMF) over HTTP or HTTPS, with the server translating Java and ActionScript objects as they pass over the wire.

A discussion of client-server integration and a detailed exploration of these components are both beyond the scope of this article. The Flex documentation, however, provides extensive information on each component. In addition, Steven's book, Developing Rich Clients with Macromedia Flex, includes a discussion on why you might choose one method over another.

Flex provides three MXML tags—HTTPService, WebService, and RemoteObject—that do a significant 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 asynchronously with 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 your application will call a mixture of external services, including one or more HTTP services, web services, methods on Java classes, LiveCycle Data Services or any other services available to you. Likewise, 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 ensure consistency in how services are declared, how they are invoked, and how their results are handled within your RIA. These are the Service Locator pattern and the Business Delegate pattern.

Locating services with the Service Locator

When several developers build against the same server-side infrastructure, they run the risk of developing convoluted code sprinkled with identical RemoteObject tags. For example, when a developer realizes he needs to make a call to a Java class, he may place deep within his component a RemoteObject tag pointing at the Java class. Meanwhile, three other developers on the team do exactly the same thing with their components, resulting in code that is difficult to understand and maintain.

The Service Locator pattern addresses this challenge by providing a repository for all services that the RIA requires. Within it, you can centralize and reuse your service tags.

The Service Locator supports each type of data access service. Application developers can fetch their services by using the correct get method (e.g. getRemoteObject), invoke methods on the service, and handle the results however they are shipped over the wire. This process allows each service to be treated in a consistent manner.

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. By convention this is done with a file called Services.mxml in the business package of your application.

Here is an example Services.mxml:

<cairngorm:ServiceLocator xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:cairngorm="/2006/cairngorm"> <mx:RemoteObject id="productService" destination="productServiceImpl" showBusyCursor="true"> </mx:RemoteObject> <mx:RemoteObject id="creditCardService" destination="creditCardServiceImpl" showBusyCursor="true"> </mx:RemoteObject> </cairngorm:ServiceLocator>

As you can see, two services are used. You use productService to fetch products from the server-side database. You use creditCardService to validate credit card information on the server before approving orders.

Both services are implemented as destinations. This means that information about the actual Java class is held in the remoting-config.xml descriptor file on the server; it is not exposed in any client-side code. This is a security best practice. It is best not to reveal information such as class names that might give a determined hacker who decompiles the Flex RIA any information about the implementation of your server-side code.

Because the Service Locator expects its services to be used multiple times in many 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 calling the service.

Invoking services on the Service Locator

After declaring services to reside on the Service Locator, you will want to invoke them.

In Cairngorm Store, when the application starts, it executes the GetProductsCommand command to fetch all products from the server-side database. As you may recall, you use the creationComplete event on the main Application tag to fire a GetProductsEvent event, which ensures that the application executes the Command class.

In the above 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" />

Here the business namespace is declared and specifies the package in which Services.mxml resides: com.adobe.cairngorm.samples.store.business.

Having declared your Service Locator, you could then place the following code into your GetProductsCommand command if you so desired:

public class GetProductsCommand implements ICommand, IResponder { public function execute( event : CairngormEvent ): void { var service:RemoteObject = ServiceLocator.getInstance().getRemoteObject( "productService" );service.getProducts(); } }

In this code, you can see how to use the Service Locator to fetch a Java service by name and then invoke methods on the service. This same approach could also be followed if the service was a web service or an HTTP service.

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.

While this would be an acceptable solution, there is a final layer of abstraction that the Cairngorm team has found very useful. We recommend using the final pattern that Cairngorm advocates, the Business Delegate pattern, as a starting point for any Cairngorm application.

Proxying Services with the Business Delegate

A particular service call, such as getProducts(), will often 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, and still another command might display the current value of the stock only. In this scenario, you could use three different services calls to service.getStockInformation( "ADBE" ) for the three different contexts.

To handle this consistently, however, Cairngorm delegates all the responsibility for business logic that locates a service and then invokes a method on it into a separate class—the Business Delegate class.

In Cairngorm Store, there are two Business Delegates, one for each of the services. Deciding how many delegates to have is a design decision left entirely up to the individual developer.

Here is the implementation of ProductDelegate.as:

package com.adobe.cairngorm.samples.store.business { import mx.rpc.IResponder; import com.adobe.cairngorm.business.ServiceLocator; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.AbstractOperation; public class ProductDelegate { public function ProductDelegate( responder : IResponder ) { this.service = ServiceLocator.getInstance().getRemoteObject( "productService" ); this.responder = responder; } public function getProducts() : void { var call : Object = service.getProducts(); call.addResponder( responder ); } private var responder : IResponder; private var service : RemoteObject; } }

A discussion of the Business Delegate makes the most sense in the context of a Command class that calls the delegate. In the case of ProductDelegate.as, this is the GetProductsCommand class:

package com.adobe.cairngorm.samples.store.command

{ import mx.rpc.IResponder; import com.adobe.cairngorm.commands.ICommand; import com.adobe.cairngorm.control.CairngormEvent; import com.adobe.cairngorm.samples.store.business.ProductDelegate; import com.adobe.cairngorm.samples.store.model.ShopModelLocator; import com.adobe.cairngorm.samples.store.util.Comparator; import mx.rpc.events.ResultEvent; import mx.rpc.events.FaultEvent; import mx.controls.Alert; import mx.collections.ICollectionView; import mx.collections.Sort; import mx.collections.SortField; import mx.utils.ArrayUtil; public class GetProductsCommand implements ICommand, IResponder { public function execute( event : CairngormEvent ): void { if( ShopModelLocator.getInstance().products == null ) { var delegate : ProductDelegate = new ProductDelegate( this ); delegate.getProducts(); } else { Alert.show( "Products already retrieved!" ); return; } } //------------------------------------------------------------ public function result( event : Object ) : void { var products : ICollectionView = ICollectionView( event.result ); var model : ShopModelLocator = ShopModelLocator.getInstance(); // sort the data var sort :Sort = new Sort(); sort.fields = [ new SortField( "name", true ) ]; products.sort = sort; products.refresh(); // set the products on the model model.selectedItem = products[ 0 ]; model.products = products; model.workflowState = ShopModelLocator.VIEWING_PRODUCTS_IN_THUMBNAILS; } //------------------------------------------------------------ public function fault( event : Object ) : void { var faultEvent : FaultEvent = FaultEvent( event ); Alert.show( "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. In this way, the Command class declares that it wants to handle the results of any calls made by the delegate. The object that wants to respond to any results is known to the delegate as the "responder."

By electing to act as a responder, the Command class implements the IResponder interface from Flex; this ensures that the developer adds a result() method to handle any delegate results and a fault() method to handle any delegate faults.

In the implementation of getProducts() on the Product Delegate, note the two lines of boilerplate code that you can add for each and every delegate method:

public function getProducts() : void { var call : Object = service.getProducts(); call.addResponder( responder ); }

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 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 result() method on the command (or invokes the fault() method on the command)

The result() method of GetProductsCommand extracts the array of products from the event representing the server results and stores them on the ShopModelLocator, while also setting selectedItem on the ShopModelLocator 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 existing 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 (MySQL and 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 are interested in the details.

Stubbing the Business Delegate

There is 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 a "contract" that both teams agree on; this contract acts 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 that creates mock value objects in ActionScript and directly calls the result() method on the calling command.

Client-side developers can then call the Business Delegate, even though 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. At Adobe Consulting, we prefer to have Command classes oblivious to the concept of server-side services by employing the Business Delegate as a proxy. The flexibility of Cairngorm, however, enables developers to build RIAs without Business Delegates if they prefer.

We find that the minimal amount of effort necessary to create these delegates and our tendency to refactor towards a Business Delegate anyway are sound reasons for including the Business Delegate pattern in all applications that we architect upon Cairngorm.

Where to go from here

You have now seen all of the design patterns that contribute to and collaborate in the Cairngorm microarchitecture.

You've learned how the Service Locator pattern can be used to encapsulate all the different service calls 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 tangible benefits to moving all service invocations into a Business Delegate class, to which you delegate all business logic calls to the server. The Business Delegate pattern offers consistency, scalability, modularity, and reuse while acting as a clear contract and single point of integration between server- and client-side development teams.

This article revisited the Command pattern and described how to write commands that implement the IResponder interface, part of the Flex framework. These commands not only use the Business Delegate pattern to invoke services, but also advertise through the IResponder interface that they wish to assume the responsibility for handling any results that the Business Delegate receives in proxying service requests on their behalf.

It is important to understand the different Flex services available to you and how to write your own Service Locator classes. Likewise, we encourage you to become comfortable with writing your own Business Delegates—by accepting an IResponder class in the constructor, liaising with the Service Locator, and adding the necessary incantations to the pending call of each service request that ensure results are routed back to the responder.

To implement the final clause in any conversation between the user and the RIA, we explained how to add methods to commands that implement the Responder interface, allowing the commands to take any service call results and update the client-side state through the Model Locator design pattern.

In Part 6, the final article in this series, we will summarize and reinforce the main concepts behind the Cairngorm architecture. What may have initially appeared complex is actually easy to apply. You'll be able to follow the rapid addition of a completely new feature to the Cairngorm Store, confident because you are using the same best practices 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

Tutorials & Samples

Tutorials

  • Flex mobile performance checklist
  • Flex and Maven with Flexmojos – Part 3: Journeyman
  • Migrating Flex 3 applications to Flex 4.5 – Part 4

Samples

  • Twitter Trends
  • Flex 4.5 reference applications
  • Mobile Trader Flex app on Android Market

Flex User Forum

More
07/25/2011 Flash Player Debug Issues - Safari 5.1 & Chrome 13
04/22/2012 Loader png - wrong color values in BitmapData
04/22/2012 HTTPService and crossdomain.xml doesn't work as expected
04/23/2012 Memory related crashes in Flex application

Flex Cookbook

More
04/06/2012 How to detect screen resize with a SkinnableComponent
02/29/2012 Embed Stage3D content inside Flex application components
02/15/2012 Custom WorkFlow Component
02/09/2012 Using Camera with a MediaContainer instead of VideoDisplay

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement