« Simple Flex 2 Messaging Example | Main | Spring <br /> 2006 »
February 26, 2006
Exploring Flex Enterprise Services 2
You've been thinking a lot lately about that next killer application you have in mind for when Flex 2 finally hits the streets. The banker in you is eager to get started with as little investment as possible, and you're in luck because Adobe has announced that there will be a free version of Flex 2 available (SDK that includes the Flex Framework and a command-line compiler). You can get away with just XML over HTTP and SOAP web services, right? Not so fast...
There's no doubt that many applications work on a very finite set of data. This might be anything from a single data record (i.e. new employee) to a few hundred data records (i.e. employee list for a department). What about a few thousand records? What about a hundred thousand records? Take for example that the average grocery store carries over 14,000 distinct items. Your average Wal-Mart store can carry over 115,000 distinct items. Certainly you're not going to load all of that into the client are you?
Perhaps you've thought a lot about what RIA means to user-interface engineering, and you've provided the user with robust filtering mechanisms. Great, now in the case of a Wal-Mart product list you've dropped the count from 115,000 to something in the order of the 14,000 that a grocery store carries. That still seems like a lot of data to be sending to the client all in one shot. What about the overhead of the SOAP packets themselves? Gutting SOAP for your own ultra-slim XML over HTTP might save you a little, but then there's the parsing that still needs to take place.
Maybe it's time for that fantastic user-interface engineering trick that we've leveraged in the HTML world for so long - paging. Now this is where your code starts to turn into spaghetti. Not only do you have service calls to get the data, you probably have an event handler to help the user along. Then when filtering is applied you have another data endpoint, and another event handler. Then when it comes time for paging, you have yet another data endpoint and yet more event handlers. Then you have to additionally code all the logic that goes into managing what page the user is on and what data needs to be retrieved.
This doesn't even take into account anything beyond getting and displaying a large set of data. What about all the other operations that an application must traditionally be called upon to perform? Creating a new record and inserting it? Managing the currency and relevance of the data that has already been displayed and updates the user might make to it? What about delete? Worst of all, how do you propose to manage the synchronization of all that data across all the clients that might be working on it? After all, this is a RIA, not your average transactional HTML presentation.
Suddenly this isn't feeling very "rich" at all, but more like a glorified web page and it will likely take you as long to code all the overhead. If only there was a way that Flex could help you out. That's where Flex Enterprise Services 2 becomes your best friend. Consider the following MXML code for a simple FES2-centric application. All the ugliness of the above problems is abstracted and fantastically absent.
<?xml version="1.0" encoding="utf-8"?>
<!-- Load the data when the application has finished rendering -->
<mx:Application pageTitle="Census Data"
creationComplete="doCreationComplete( event )"
xmlns:mx="http://www.macromedia.com/2005/mxml">
<mx:Script>
<![CDATA[
// Leverage the data collections and data services
import mx.collections.*;
import mx.data.*;
import mx.rpc.events.*;
// Using compiler metadata to indicate bindable properties
// The property in this case is a collection
// Collections are used to abstract data from operations on that data
// This collection is populated by the data service and bound
// to a data grid
[Bindable]
public var income:ArrayCollection = null;
// Reference to the data service we'll be using
public var ds:DataService = null;
// Event handler called when the application has finished rendering
// Initializes the collection and tells the data service to fill it
public function doCreationComplete( event:Event ):void {
income = new ArrayCollection();
// Data service configured and names in server configuration
ds = new DataService( "census" );
ds.fill( income );
}
]]>
</mx:Script>
<!-- The data grid being used to display to data service data -->
<!-- Also allows for editable records that are immediately updated
in the database and across clients -->
<!-- Data is bound to the collection that is previously defined -->
<mx:DataGrid width="100%" height="100%" dataProvider="{income}" editable="true">
<mx:columns>
<mx:Array>
<mx:DataGridColumn columnName="age" headerText="Age" />
<mx:DataGridColumn columnName="classOfWorker" headerText="Class of Worker" />
<mx:DataGridColumn columnName="education" headerText="Education" />
<mx:DataGridColumn columnName="gender" headerText="Gender" />
<mx:DataGridColumn columnName="maritalStatus" headerText="Marital Status" />
<mx:DataGridColumn columnName="race" headerText="Race" />>
</mx:Array>
</mx:columns>
</mx:DataGrid>
</mx:Application>
This very small amount of code handles implicit paging of editable data sets and synchronization across connected clients. There are fifty records being sent to the client at any given time (which can be developer defined) based on the users position in that data set (20,000 records). Additionally, when changes are made to a record (notice the "editable" property on the DataGrid), those changes are automatically made in the database, and sent to other connected clients (thanks to the messaging infrastructure). All in ~fifty lines of code? Welcome to the world of Flex Enterprise Services 2!
What’s going on at the server is a combination of a few different things.
The first is a Java object that we'll call an "assembler". Most importantly, the assembler has methods that handle basic CRUD operations (create, read, update and delete for the uninitiated). The assembler also has methods that take developer-defined arguments for filtered queries (e.g. give me all the records where the age is greater than twenty). Finally the assembler has a method that handles synchronization of any newly applied data and conflict resolution across clients.
Note that FES2 doesn't define how that conflict resolution takes place, it simply provides the hooks - it's up to the developer to decide who gets first access on updating the data in the database.
The implementation of the assembler is also up to the developer, but most commonly it will leverage a data access object, which is the second FES2 touch point. Providing a data access object (DAO) insulates the assembler from changes to the infrastructure. For example, what if we changed the data store from a database, to an XML file? The assembler doesn't need to know about any of this, so it's good practice to separate the two. ActionScript, DAO and Hibernate adapters will ship with FES2, but you can also implement your own.
In the case of the DAO, it is expected that a value object will also be created in both Java and ActionScript for the data that is actually being transferred.
Finally we need to tell FES2 what to do with these objects. It needs to know what methods in the assembler tie to what CRUD operation; it needs to know the unique identifier for the objects; and it needs to know a little about how you'd like it to handle accessing that assembler. For example, you might want fifty records returned at a time because that's all that the client has room to display. Or perhaps, based on your testing (another great FES2 feature), a larger value is more appropriate.
That's pretty much all that you need to think about. It's a clean and elegant abstraction of the data and business tiers from the client tier. A Flex developer focuses on what the application needs to do with the data, not on the business tier endpoints to call to get that data. There are a couple very lightweight examples of using the data services that ship with FES2 Beta 1 centered on contact management.
For reference, I've also reworked Matt Chotin's classic MAX presentation content into an FES2 example. The attached code leverages Matt's census data loaded in bulk into a MySQL database (no normalization). I also leverage JDBC connection pooling for efficiency. My configuration files and Matt's data files are absent from the attached code. If you want them, leave a comment. We'll see what we can arrange based on demand.
Posted by khoyt at February 26, 2006 09:03 PM
Comments
I'd love to get the data file in particular. I've been really excited about the automatic data management in FES2 ever since I saw it demonstrated at MAX, but the significance of these features is difficult to convey by just describing them verbally. When people see a demo of it in action, though, they instantly get it. Having that data would definitely help me do those kind of demos.
Posted by: Kristopher Schultz at February 27, 2006 06:26 AM
Kristopher,
If you follow the link on Matt Chotin's name, you'll go to an entry of his that contains the data files. I used the "censusincome.csv" file and imported it to MySQL. I started off in Access, but as you can imagine, it's scalability left something to be desired under this kind of load.
Thanks for reading,
Kevin
Posted by: Kevin Hoyt at February 27, 2006 07:54 AM
Great Post Kevin, it's nice to see some long posts about FES2!
Posted by: Ryan Stewart at February 27, 2006 09:10 AM
What do you do if you're coming from the .NET world though? Can I leverage FES2 when my backend is implemented in .NET?
Posted by: ashif at February 27, 2006 11:31 AM
Ashif,
We don't have a great answer for the FES use-cases and .NET just yet. We are eager to hear more about how .NET developers might want to integrate with their back-office systems. If you'd like to email me directly with more information, please do so and I'll pass your comments on to the engineering team.
Thanks,
Kevin
Posted by: Kevin Hoyt at February 28, 2006 07:09 AM
Does anyone have a simple working example of paging, include the .mxml and flex-data-service.xml file?
Posted by: jeff lage at March 24, 2006 11:49 AM
Yes, I would also like to see an example of datagrid with paging implemented. Please post it if you have a running example.
Posted by: parinda at July 14, 2006 09:11 AM
I want also paging!
Posted by: Sjoerd at November 21, 2006 05:57 AM
Yes, I would also like to see an example of datagrid with paging implemented. Please post it if you have a running example.
Posted by: Rahul at January 4, 2007 09:35 PM