Tuesday, October 11, 2011

Yet Another Micro Architecture for Flex RIA and RMA

The Holistic micro-architecture framework for building RIAs and RMAs (Rich Mobile Applications) "borrows" from Robotlegs, PureMVC, Cairngorm, SWIZAS3Signals and the SpringFramework. Each has one or two things that I really like about it, but what I wanted is to bring all these things into one simple, very lightweight framework that enables me to quickly and more importantly methodically build mobile, web and desktop applications. This Holistic API is designed to work on top of either the Flex web or mobile framework and takes advantage of the Flex compiler, environment and lifecycle. Several "design patterns" are utilized in the API, such as Model-View-Controller, Loose Coupling, Locator, Usage of Interface, Delegation, Dependency Injection, Separation of Concerns and Inversion Of Control, not sure if some of latter are pure design patterns per GoF, but bear with me :-) One thing that is heavily relied on, is programming to convention versus programming to configuration.

MVC

Looking at the above diagram, the state of an application resides in the Model. The model is a set of non visual properties, where some properties are annotated using the [Bindable] metadata, in such that a change event will be dispatched whenever that property is mutated. This [Bindable] metadata is an indication that this property is represented by a view.
public class Model {
    [Bindable]
    public var text:String;
}
Views are subclasses of UIComponents and are bound using curly braces (I call them 'magic' braces) to the Model to represent the state of the application based on the view capabilities.
<s:label text="{model.text}"/>
In the above example, this Label instance is representing the model 'text' property and any changes to the 'text' value will be auto-magically shown in the label location on the screen. For a more complex example; a property that is a list of features can be bound to a map view and the features will be drawn as points on the map. At the same time, that same list can be bound to a data grid where each feature will be represented as a row in that grid. A model can have multiple view representations in an application.
Now, if a view wants to modify the model, it does so using a controller. A view is not, I repeat, is not allowed to mutate the model. Only a controller is allowed to mutate the model. This is very important as a convention. All the logic to mutate the model should reside in a controller even if it means that the logic is a single line implementation. Trust me on this, when developing the application, in the beginning this might be a single line. But... along the application development process, this will get more elaborated per the application requirements. You will be tempted by the programming devils to "touch" the model from the view and you will come to regret it later on. So be resilient and do the right thing !
Enough preaching. So how does a view tell a controller to mutate the model ? Simple, using signals. A signal is a glorified event with integrated event dispatching enabling a loose coupling between the view and the controller.
The following is the signature of the static 'send' function in the Signal class:
public static function send(type:String,...args):void
The first required string argument is the signal type. This string is very important in our convention over configuration design as we will see later on. A signal can optionally carry additional information such as in the following example:
<s:textinput id="ti"/>
<s:button click="Signal.send('submit',ti.text)" label="{model.text}"/>
When the user clicks on the Button instance, a signal of type 'submit' is sent along with the text that was entered in the TextInput instance.
Now, I need 'something' to receive that signal and act on it. This something is a controller. Again, relying on convention over configuration, I will create a controller named 'SubmitController'. Note the prefix 'Submit', it is the same as the signal type. Again this is the convention over configuration that is working in my favor where by writing pseudo-self documenting code. I can look at my list of controllers in my IDE and can tell immediately from the names what signal is handled by what class. Yes, I will have a lot of controllers, but this divide and conquer approach enables me to do one thing and one thing very well and separate my concerns.
In the controller class implementation, to handle the 'submit' signal, I should and must have a function named 'submit' that accepts one argument of type String like the following:
[Signal]
public function submit(text:String):void
{
  ...
}
Note the [Signal] metadata on the function declaration. See, as a Flex developer, you are already familiar with and using the built-in annotations such as [Bindable]. But Flex enables a developer to create his/her own metadata that will be attached to the class in question for introspection, cool, eh ? Back to signals, one more example to solidify the association of signals to controllers - if you send a signal of the form:
Signal.send('foo', 123, 'text', new Date());
To handle that signal, you should have the following controller declaration:
public class FooController {
    [Signal]
    public function foo( nume:Number, text:String, now:Date):void {
      ...
    }
}
Note that the order of the handler function arguments should match the order and type of the signal arguments. 123 -> nume, 'text' -> text, new Date() -> now. What makes this pretty neat is the independence of the hardwiring signal dispatching mechanism and the handler is just a function that can be unit tested, more on that later.
Applications need to communicate with the outside world, say for example you want to locate an address using an in-the-cloud-locator service. Controllers do not communicate with the outside world, they delegate that external communication to a service. That service will use the correct protocol and payload format to talk to the external service be SOAP, REST, RemoteService in XML, JSON or AMF or whatever. To enable different implementations of these protocols, an interface is declared and is injected into the controller for usage like as follows:
public class LocateController {

    [Inject]
    public var locateService:ILocateService;

    [Signal]
    public function locate(address:String):void
    {
        locateService.locate(address,
            new AsyncResponder(resultHandler, faultHandler));
    }
}
The locateService variable is assigned at runtime using inversion of control and when the 'locate' signal is sent, it is handled by the 'locate' function who delegates it to the ILocateService implementation. The [Inject] metadata is for more than injecting service implementations. Here is another usage to overcome AS3 language constraints and make your code more testable. Say you start a project and Signal A is sent, you go and you write Controller A to handle the signal. Now you have to write another controller B to handle signal B (remember SoC :-) but you find that Controller A and B will share some code. Since you are a good OO developer, you create a super class S that has the common code and make Controller A and Controller B subclass S. You feeling pretty good, onto Controller C to handle signal C. But wait a minute, some code from Controller B can be shared with Controller C. Ok, you create a super class D and subclass. But wait a minute..., AS3 is a single inheritance model, than means Controller B cannot subclass super class S and D at the same time. This is where composition is better that inheritance where now I can move the common code to class S and class D and inject those classes into controller A,B and C.
public class AController {
    [Inject]
    public var refS:ClassS;

    [Signal]
    public function doA(val:*):void {
        refS.doS(val);
    }
}

public class BController {
    [Inject]
    public var refD:ClassD;
    
    [Inject]
    public var refS:ClassS;

    [Signal]
    public function doB(val:*):void {
        refS.doS(val);
        refD.doD(val);
    }
}

public class CController {
    [Inject]
    public var refD:ClassD;

    [Signal]
    public function doC(val:*):void {
        refD.doD(val);
    }
}
Cool ? Onward, something _has_ to wire all these pieces together and that something is a Registry instance that is declared in the main application mxml as follows:
<fx:Declarations>
    <h:Registry id="registry">
        ...
   </h:Registry>
</fx:Declarations>
The children of the Registry are all the application controllers and all injectable delegates and services. So using the above example:
<h:Registry id="registry">
   <m:Model/>
    <c:ClassS/>
    <c:ClassD/>
    <s:AController/>
    <s:BController/>
    <s:CController/>
</h:Registry>
Taking advantage of the declarative nature of Flex, I declare the registry children that gets translated into ActionScript instantiation, whereupon creation completion, the registry will introspect each child for [Inject] metadata and invokes the setter with the appropriate type instances. Next, the [Signal] metadata are located and a proxy object is created wrapping the annotated function as event listener to the Signals (remember, signals are nothing more than glorified events). All this introspection by the Registry is perform using the as3-commons-reflect library (url). Going back to programing to interfaces and having multiple implementation of an interface in the Registry, how is the injection resolved ? Well, by default the first implementation is injected. But what if I want a specific implementation ? here is the solution:

<h:Registry>
    <c:RestService/>
    <c:SoapService id="soapService"/>
    <c:FooController/>
    <c:BarController/>
</h:Registry>

[Register(name="restService")]
public class RestService Implements IService {
  ...
}

public class FooController {
  [Inject]
  public var restService:IService;
  ...
}

public class BarController {
  [Inject(name="soapService")]
  public var service:IService;
  ...
}

There is a lot packed in this example and there is a lot of conventions, so stay with me. The registry is declared with a couple of services and controllers. Note that the SoapController is registered with the "soapController" id. This enables the BarController to be injected with that specific implementation of the IService interface via the name attribute in the inject metadata. Next, the RestService is registered with the Registry with the name "restService" as declared in the class metadata. Now (magic time), the FooController is injected with the RestService instance despite the absence of the name attribute in the inject metadata because the _variable_ name is same as the class registration. Pretty powerful, I know, mind blowing!

Ok, last but not least, unit testing. Actually, if you do TDD, that should be first. The holistic framework looks for simple interfaces, classes and functions, and with the built-in capabilities of unit testing and code coverage add-on to FlashBuilder, there is no excuse not to test your code. Whole books and articles have been written about Flex unit testing so google them.

Like usual all the source code is available here. I drink my own champagne, what you will find is the Flex unit test project that includes the holistic library.

Have fun.

Update: I created a very simple project that demonstrated the usage of the Holistic framework. As I said it is a simple application that displays a data grid that is bound to a list property in the model. Below the grid is a form that enables you to enter a first name and last name. When you click on the submit button, a signal is sent with the entered info. A handler will received the info and will delegate it to a service that uppercases the values and adds them to the list.

Map Tiles For Offline Usage Using ArcGIS API for Flex

So… Google introduced an offline feature to their mobile mapping application, enabling you to view map tiles when you are disconnected from the network. This is pretty neat and very useful now that local storage is so “abundant” on mobile devices. In this post, I would like to show you how to use the mobile device local storage for offline tile retrieval using the ArcGIS API for Flex. When we built the API, we always had the vision of extensibility to enable people to do things that we did not think about. One of then was to enable the control of the URL from where the tiles will be retrieved. A while back, I did such an implementation using Amazon S3. So, I rehashed that code using Adobe AIR File capabilities. The demo application that I am featuring here operates in two modes; an online mode and an offline mode. In the online mode, I keep a set all downloaded tiles for a particular viewing session. Before I go offline, I download the map server metadata and all the visited tiles to my device local storage. The AIR runtime can notify an application when the network connectivity changes. This enables me to put the application in offline mode and when I start panning and zooming, rather than retrieving the tiles from the cloud, I retrieve the tiles from my local storage. Pretty neat, eh ? So here is the code:
public class OfflineTiledMapServiceLayer extends ArcGISTiledMapServiceLayer
{
  override protected function getTileURL(
     level:Number,
     row:Number,
     col:Number
  ):URLRequest
  {
    var urlRequest:URLRequest;

    if (Model.instance.isOffline)
    {
      urlRequest = new URLRequest(
        "app-storage:/l" + level + "r" + row + "c" + col);
    }
    else
    {
      urlRequest = super.getTileURL(level, row, col);
      if (urlRequest.url in Model.instance.cacheItemDict === false)
      {
        const item:CacheItem = new CacheItem();
        item.urlRequest = urlRequest;
        item.level = level;
        item.row = row;
        item.col = col;
        Model.instance.cacheItemDict[urlRequest.url] = item;
      }
   }

   return urlRequest;
 }
}
The OfflineTiledMapServiceLayer extends the ArcGISTiledMapServiceLayer class and overrides the getTileURL function. This function is invoked to get the tile URL for a particular map level, row and column. If the application mode is offline, then the “app-storage” url scheme is used and the path is in the form of “l”+level+”r”+row+”c”+column. If the application mode is online, then the super.getTileURL is invoked and we keep a set of visited URLs. Using the application settings view, the application has the option to download the map server metadata and iterate over the visited tiles and save the bitmap images to the local storage as defined by File.applicationStorageDirectory. The AIR runtime has the capability to notify the application of a network change. When this occurs, I ping a URL (www.google.com) using the HTTPService to determine if this is a connect or a disconnect change thus putting the application in an online or offline state.
The application can be written in such a way that any visited tile can automatically be saved to the local storage, I leave that as an exercise for the reader :-)
Like usual, all the source code is available here.
NOTE: This sample application is for demonstration purposes ONLY and is intended to be used with your own legally cacheable tiles - I am not a lawyer, but I am pretty sure that it is not legal to save locally the ArcGIS.com accessible tiles.