Thursday, April 1, 2010

More than MVC framework for Flex : Mate

Recently at work place I was working on complex GUI screen which was to be designed in Flex. Flex has quite nice capabilities : Making beautiful GUI containing charts, widgets with minimal efforts and getting data from java-based-server-side with RemoteObject. But I guess as application will get complex(Do check grooveshark.com to see how rich and complex but beautiful GUI can be created with Flex) I needed some way of structuring and designing application so anybody can understand and extend application without reading thousands of lines of action script code. Being java programmer (framework based eco-system) naturally I thought on the lines of Struts, MVC framework. But then I felt need of spring like container too where I can write/design each component separately, test them and inject and wire them in main application. There are lots of framework in flex : Cairngorm, pureMVC and Mate. Naturally first pick was Cairngorm since its official adobe framework. While browsing through HelloWorld program, I thought why I am needed to to make so many framework specific classes. Last update date on download site was very old : 30th May 2007. Then I learned about Mate : a wonderful framework which allows structuring of application in very unobtrusive way with very small learning curve. It was quite easy for me to help other team members understand new design with this framework.

Mate uses flex eventing. So with Model-View-Controller, View generates events like Submit-Form which then you can "map" to one or more Controllers. The best feature of this framework is "Injection". It injects model into controller and view so once you change model in Controller methods View updates it self. With Flex data binding and Mate injection this becomes quite powerful and very simple design for complex GUI. Mate EventMap tag allows declarative coding thus allows rapid testing and prototyping. When you look at Mate EventMap you will come to know what Application is doing, its high-level components. - your design - exactly what framework should do. Mate allowed me structure my application and set discipline.

Say for example on clicking on "submit" button, you want to show make remote call, get data, update couple of labels on screen and put data into Grid also calculate Total Amount from all records and based on some "Value" you want to show some Signal like Yellow, Amber or Green indicating current status. Such screen can be described by simple EventMap declaration as follows. View can be implemented with its own Panels : SearchPanel and DisplayPanel. SearchController will host all activity specific code like calculating Totals or Summary etc.

EventMap








  1.  <EventHandlers type="{SearchEvent.SEARCH}">

  2.     <!-- call the remoting service -->

  3.     <RemoteObjectInvoker instance="{services.productService}" method="search" arguments="{event.searchCriteria1,event.searchCriteria1}">

  4.         <!-- result sequence gets executed when service returns with a result -->

  5.         <resultHandlers>

  6.         <MethodInvoker generator="{SearchController}" method="setGridData" arguments="{resultObject}"/>                

  7.         <MethodInvoker generator="{SummaryCalculator}" method="calculateSummary" arguments="{resultObject}"/>                

  8.         <MethodInvoker generator="{SignalIndicator}" method="calculateAndIndicateState" arguments="{resultObject}"/>                

  9.         </resultHandlers>

  10.         <faultHandlers>

  11.         <CallBack method="handleFault" arguments="{fault.faultDetail}"/>

  12.         </faultHandlers>

  13.     </RemoteObjectInvoker>

  14. </EventHandlers>

  15.  





View code can be refactored into two panels : SearchPanel and DisplayPanel SearchPanel looks like as follows :

SearchPanel


  1. <mx:Script>

  2.        <![CDATA[

  3.            import mate.events.*;

  4.            import mx.controls.Alert;

  5.            import mx.collections.*;

  6.            

  7.            private function fireSearch():void

  8.            {

  9.                var event:MessageEvent = new SearchEvent(SearchEvent.SEARCH, true);

  10.                event.searchCriteria1 = textInput1.text;

  11.         event.searchCriteria2 = textInput2.text;

  12.                dispatchEvent(event);

  13.            }

  14.            

  15.                ]]>

  16.    </mx:Script>

  17.  

  18.  <mx:Button id="searchBtn" label="Search" width="100" click="fireSearch()"/>




Where as DisplayPanel looks like as follows :

DisplayPanel


  1. <mx:Panel>

  2.     <mx:Script>

  3.     <![CDATA[

  4.         import mate.events.*;

  5.         import mx.controls.Alert;

  6.         import mx.collections.*;

  7.         import mate.model.*;

  8.  

  9.         [Bindable]

  10.         public var searchResult:SearchResultVO;

  11.       ]]>

  12.     </mx:Script>

  13.  

  14.  

  15.     <mx:VBox label="Search Result">

  16.         <mx:DataGrid id="dataGrid" width="350" height="200" dataProvider="{searchResult.Data}"/>

  17.     </mx:VBox>

  18. </mx:Panel>




and code below injects model into controller and DisplayPanel. The way it works like Spring context's singlton bean so same instance is shared and below tag says : DisplayPanel.searchResult = SearchController.currentResultSet

EventMap - Injector


  1. <Injectors target="{DisplayPanel}" >

  2.         <PropertyInjector targetKey="searchResult" source="{SearchController}" sourceKey="currentResultSet" />

  3.  </Injectors>




Below is code for Controller which requires its own Binding when currentResultSet changes :

SearchController



  1. package mate.controller

  2. {    

  3.     import flash.events.Event;

  4.     import flash.events.EventDispatcher;

  5.     import mx.controls.Alert;

  6.     import mx.collections.ArrayCollection;

  7.     import mate.model.*;

  8.    

  9.     public class SearchController extends EventDispatcher

  10.     {    

  11.         private var _currentResultSet:SearchResultVO;

  12.        

  13.         [Bindable (event="currentSetChange")]

  14.         public function get currentResultSet():SearchResultVO

  15.         {

  16.             return _currentResultSet;

  17.         }

  18.        

  19.         public function setGridData(result:SearchResultVO):void

  20.         {

  21.            // Do other processing if required....

  22.             _currentSet = result;

  23.             dispatchEvent( new Event('currentSetChange'))

  24.         }

  25.     }

  26. }  



One more good feature if Mate is that it has MockService interface where you can write dummy remote service as part of Flex application itself. This allows developers to work independently when server-side services are not ready or avaialable.

  1.  <MockRemoteObject id="helloService" showBusyCursor="true" delay="1" mockGenerator="{MockHelloService}"/>

  2.  



Welcome to awesomeness of Mate.
Tushar