by Dave Flatley
Dave Flatley

Created

28 June 2010

Requirements

   
Prerequisite knowledge
Some knowledge of ActionScript 3, Flex 4, Flash Builder, and object-oriented programming concepts will be helpful. A basic understanding of BlazeDS, Java, and MySQL will be beneficial – but not necessary - in understanding the server-side functionality that the Flex client is interacting with to receive its data.
User level
Intermediate
 
Required 
Flash Builder (Download trial)
Sample files
This article is Part 4 of a series of articles and tutorials centered on a sales dashboard application built using Flex and the Adobe Flash Platform. The individual articles in the series are designed to stand on their own, so you can read all of them or just the ones that interest you, in whatever order you like.
 
Part 4 explains how to get the DigiPri Widgets sales dashboard sample application up and running in Adobe Flash Builder 4 and explores some of the underlying code. Part 1 introduces the fictitious company DigiPri Widgets, explains the reasons behind selecting Flex, and provides a tour of the dashboard application. Part 2 details the server setup, and Part 3 takes a closer look at the application and its architecture. This article covers the following topics:
 

 
Setting up the project in Flash Builder 4

Follow these steps to set up the project in Flash Builder:
 
  1. Download and extract the sample files for this article.
  2. Start Flash Builder and choose File > Import Flex Project (FXP).
  3. Browse to and select the AdobeCRM.fxp sample file.
  4. Click Finish.
Now that you've imported the Flash Builder project, you can start to explore the code to see how the application works. In the following sections, you'll see how some of the main pieces of the dashboard come together to make the DigiPri Widgets sales dashboard application work.
 
If you have set up the server application to run locally based on Part 2: Setting up the server application, then you can use the deployed server-side code to work with this Flash Builder project. You need to ensure that the channel definitions and endpoints in your BlazeDS services-config.xml file (located in the services folder) are properly configured; for example:
 
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel"> <endpoint url="http://localhost:8400/adobeCRM/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/> </channel-definition>
This topic is covered in more detail in the Using BlazeDS section later in this article.
 

 
Server-side communication

To keep this project as straightforward and flexible as possible, none of the available micro-architecture frameworks was used. Instead, the project relies on a few basic design patterns to enable communication with the server-side application and retrieve data for the charts.
 
The Flex application uses commands to retrieve data from the server. See Part 3: Understanding the dashboard application for a more detail explanation of the command mechanism.
 
Open the commands.CommandAdapter class to take a closer look.
 
Each class that extends CommandAdapter must override the execute method and the CommandAdapter adds itself as the responder for the result of a server call.
 
 
Inside the BaseChart
For a better understanding of the responder pattern, take a look at the components.reports.BaseChart class.
 
In the callDataProviderCommand() method, the command variable is set dynamically based on the class name that comes through in the reportBean (loaded from the reports.xml file). For example, when retrieving the top 10 client deals, this variable is set to the commands.GetTop10ClientDealsCommand class.
 
protected function callDataProviderCommand() : void { var command : CommandAdapter; var commandClass : Object = getDefinitionByName( reportBean.command ); if ( reportBean && reportBean.commandArgs && reportBean.commandArgs.length > 0 ) { command = new commandClass( reportBean.commandArgs ); } else { command = new commandClass(); } command.addCallBack( handleCommandResult ).execute(); }
The command variable adds itself as the responder and sets the BaseChart's handleCommandResult() method as the handler for the final result from the server. It also calls the command's execute method, which in this example is GetTop10ClientDealsCommand.execute() .
 
Here is the overridden execute method from the commands.GetTop10ClientDealsCommand class:
 
public override function execute() : void { serviceFactory.getClientDealService( this ).getTop10ClientDeals(); }
 
ServiceFactory
The serviceFactory instance is a local reference to a singleton class, which is the final step in the server tier for the Flex side in this dashboard application. The execute method in the commands.GetTop10ClientDealsCommand class (shown in the previous section) instantiates a RemoteObject, named clientDealService, on the ServiceFactory singleton. It provides access to the possible operations of that command. Look at the IClientDealService interface to see the contract for the remaining method implementations for clientDealService :
 
public interface IClientDealService { function getAllClientDeals() : AsyncToken; function getAllClientDealsByStatus() : AsyncToken; function getClientDealsByStatusTypeId( status : StatusType ) : AsyncToken; function getTop10ClientDeals() : AsyncToken; function getTop10ClientDealsByRegionId( region : Region ) : AsyncToken; function getTop10ClientDealsByUserId( user : User, lBoundDate : Date = null, uBoundDate : Date = null ) : AsyncToken; }
 
Using BlazeDS
BlazeDS is the free server-based Java remoting and web messaging technology that enables developers to easily connect to back-end distributed data and push data in real-time to Flex and AIR front-end client applications.  For the DigiPri Widgets sales dashboard application, it's used to connect the dashboard to the server-side Java logic, which queries the database and returns the data to the Flex client.
 
The two XML configuration files needed for the dashboard application are services-config.xml and remoting-config.xml; they are located in the services folder.
 
The remoting-config.xml file contains a list of destination tags. These destinations map Java resources to calls from the Flex application; for example:
 
<destination id="clientDealService"> <properties> <source>com.adobe.community.adobecrm.service.impl.ClientDealServiceImpl</source> </properties> </destination>
In the above snippet, the destination that can be called from Flex (named clientDealService) maps to the ClientDealServiceImpl Java class.
 
Inside the services-config.xml file, you'll see the channel definitions, which declare endpoints for use with BlazeDS on the localhost. If you deploy Tomcat on a nonstandard port, you'll need to ensure the url set correctly. With a typical install of the BlazeDS turnkey edition, here is the correct channel-definition :
 
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel"> <endpoint url="http://localhost:8400/adobeCRM/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/> </channel-definition>
In the code, the clientDealService destination property is set to "clientDealService" in the getClientDealService() method of the ServiceFactory singleton:
 
public function getClientDealService( resp : IResponder ) : IClientDealService { var destPath : String = "clientDealService"; // create new remote service, pass it the remote object and the responder and return it if ( !clientDealService ) { clientDealService = new RemoteObject(); RemoteObject( clientDealService ).destination = destPath; RemoteObject( clientDealService ).showBusyCursor = true; } returnnew ClientDealServiceRemote( clientDealService , resp ); }
The value of this destination property matches a destination node's id property in the services/remoting-config.xml file, which is a logical name that is mapped to a fully qualified Java class on the server:
 
<destination id="clientDealService"> <properties> <source>com.adobe.community.adobecrm.service.impl.ClientDealServiceImpl</source> </properties> </destination>
In the model.beans.ClientDeal class, the following RemoteClass metadata tag is set at the top:
 
[RemoteClass( alias="com.adobe.community.adobecrm.domain.ClientDeal" )]
This class is the typed ActionScript object deserialized from the returned server-side method. An important thing to note is that although this application uses a Java back-end, the Flex code would behave exactly the same with other server-side implementations, including ColdFusion or PHP.
 

 
Designing the dashboard user interface

The DigiPri Widgets application uses the latest version of the Flex framework, which introduced Spark component skins and new CSS styling conventions to help developers separate code concerns.
 
 
Spark skins
With the Spark skinning conventions, you have complete control over how your components look and feel, and you can quickly change the way a component looks without ever touching its actual functionality.
 
Among the first lines in the dashboard's code (in AdobeCRM.mxml), you'll notice a new property of the Spark Application tag called skinClass :
 
skinClass="assets.skins.ApplicationBackgroundSkin"
Open the ApplicationBackgroundSkin.mxml file in the src.assets.skins package and look at its structure. The dashboard application uses a simple pair of gradient-filled Rect objects, one for the top navigation area (the light silver gradient) and one for the background behind the charts (the black to gray gradient).
 
To fulfill the skinning contract for the Application component, this skin class contains the basic states, contentGroup container, and HostComponent metadata tag. The HostComponent tag declares which component the skin is going to be used for. The states are predefined by each component. The contentGroup container provides the guidelines for placing child elements and specifies any layout restrictions.
 
The actual design of the component in this case consists of the two Rect objects with their gradient colors. A developer could use images or CSS styles in the skin's implementation, or switch to another skins entirely just by setting the skinClass property of the Application tag.
 
Inside the assets.skins package, you'll see a number of other component skins with different styles. These are used mainly for buttons throughout the application.
 
 
CSS Styles
You can also apply Spark skins with style sheets. In the main.css file within the assets package, you'll find the following selectors set for the reports and BaseChart.
 
.drillDownReport { skinClass: ClassReference("assets.skins.ReportSkin"); } .baseChart { skinClass: ClassReference("assets.skins.ChartSkin"); }
Each one behaves exactly the same as setting the skinClass property directly on a component; this is just another way of specifying a skin, or any other CSS style you'd want to associate with a given component.
 
With Spark skins, there's no limit to the customization you can perform on predefined components or components of your own creation.
 
Another benefit of skinning components with Flex 4 is the designer/developer workflow. Because Flex 4 skins separate the component's appearance from its underlying functionality, designers and developers can proceed unhindered in their respective workflows and easily make changes without affecting each other or missing deadlines. If a designer was to receive a work order to change the DigiPri Widgets report's background skin, it would have no impact on development of the report's functionality. When the new design was completed, the developer can replace the existing skin with the new skin in no time.
 
 
Animating the reports
When a report is maximized, it zooms in to take up more of the screen's real estate. The other reports in the ExtendedDragDropTileGroup container zoom along with the selected report to provide a 3D effect. This is done by zooming in on all of the reports while increasing the horizontalGap and verticalGap properties of the ExtendedDragDropTileGroup container.
 
The dashboard makes use of the new Spark Animate and Scale effects (contained in a Parallel effect) to produce the animation. The Animate class allows you to animate any property of an object over a specified amount of time; for example:
 
var s:SimpleMotionPath = new SimpleMotionPath(); s.valueFrom = 10; s.valueTo = 30; s.property = "horizontalGap"; var s2:SimpleMotionPath = new SimpleMotionPath(); s2.valueFrom = 10; s2.valueTo = 30; s2.property = "verticalGap"; var v:Vector.<MotionPath> = new Vector.<MotionPath>(); v.push( s ); v.push( s2 ); var a:Animate = new Animate(); a.motionPaths = v;
In the above code, SimpleMotionPath objects are used to specify valueFrom , valueTo , and property . The property values of each SimpleMotionPath object are set to the horizontalGap and verticalGap of the ExtendedDragDropTileGroup. These settings instruct the Animate class to increase these gaps over the span of time set on the Parallel effect, which contains the entire set of effects.
 
The SimpleMotionPath objects are contained in a Vector, which is then set on the motionPaths property of the Animate class. When the user clicks the maximize button of a report, the Parallel created in the maxBtn_ClickHandler() method of the ExtendedDragDropTileGroup container sets the animation based on some coordinates and the view produces the 3D zoom effect to show the reports in greater detail.
 
Upon minimizing, a similar animation approach is used, with reversed settings to zoom the reports back to their original position and reset the gap values.
 
There are a number of other Spark effects that can be used produce this kind of dashboard animation, but for greater control over the specifics of the animation, the Animate class is ideal.
 

 
Where to go from here

If you have not done so already, you may want to read Part 1, Part 2, and Part 3 of this series on the DigiPri Widget sales dashboard application to learn more about it.
 
There are several ways to expand your Flex skills and knowledge using the sample application. For example, you could create a new server-side application in another language that mimics the Java used in this project, and then use the same Flex front-end to access it with no code changes.
 
Alternatively, you could make your own reports within the dashboard using new server calls and custom server-side methods that you create. Using the existing Java code as a model, you can create your own method to query the database and return a new set of data to Flex to show in the My Dashboard section.
 
To keep this sample application as straightforward and flexible as possible, a generic ultra-lightweight services framework was used rather than one of the many open-source frameworks available for Flex, such as Spring and Hibernate. Many of these frameworks use the same type of logic and patterns; however, they all have their own learning curve. Developers who are new to Flex are encouraged to explore more of these frameworks to find what works for their application's particular needs.
 
Here are some resources for further reading on Flex 4, Flash Builder, and the Spark architecture: