Using ‘Proxy’ For Loading & Accessing Config Files

Configuration Files

Externalising some of your application’s settings in to config files is something most (hopefully all) of us do when writing Flex & AIR apps. It becomes almost essential when writing apps that may be moved around (e.g.  say your place of work has a development server, a UAT/staging server and a production server – you don’t want to have to recompile your app each time you move from one server to the other … which is what you’d have to do if your application had things like URLs hardcoded in to them).

If you don’t yet use config files, consider how they would work given the above situation.
On our DEV server we’d have a file called ‘config.xml’, on our UAT server we’d have a file called ‘config.xml’, and on our PROD server we’d have a file called ‘config.xml’ too. Each file would contain settings specific to that particular environment. EG:

[as3]
//IN DEV CONFIG
<prop id="remotingEndpoint" value="http://localhost/weborb30/weborb.aspx"/>

//IN PROD CONFIG
<prop id="remotingEndpoint" value="http:/mycompanywebsite.com/services/weborb.aspx"/>
[/as3]

In our Flex app we would do the same thing regardless:

[as3]
//IN OUR FLEX APP (not showing full tag here, but you get the idea)
<mx:RemoteObject
destination="GenericDestination"
endpoint="{appSettings.remotingEndpoint}"/>
[/as3]

The key point is that the Flex app doesn’t have to be recompiled when it is moved from server to server – it just picks up the local config settings for each environment.

A Common Approach To Creating/Loading Configs

One way people deal with config files is to create a class which loads in some settings file, usually as XML. This class most likely defines properties which correspond to the properties in the XML – the idea being that you populate the class properties from the XML properties. There are more efficient variations on this approach, but doing it that way is common – I was prompted to write this post after seeing someone doing just this. It has several drawbacks though. For example, each time you add a property to your XML you have to add that property (or getter method) to your class as well. You also end up having one class per config file, so it’s not particularly reusable.

The flash.utils.Proxy Approach To Creating/Loading Configs

What would be nice is if we had an easy way to load in our config XML file and have all the properties instantly available via our class. This is where flash.utils.Proxy comes in. There are four things we need to do in order to get this to work (five if we want our class to dispatch events as well):

  1. Make our class dynamic
  2. Extend flash.utils.Proxy
  3. Override its ‘getProperty’ method
  4. Use the flash_proxy namespace (in order to be able to override getProperty)
  5. (optional) Implement IEventDispatcher

I’ll go over the key points now but it’s easier to see it in action so I would recommend downloading this example file ( in FlexBuilder choose file->import->existing projects in to workspace … select ‘archive file’ and browse to the file you downloaded).

(1) Our class is declared using the dynamic keyword – essentially this allows other classes to request any properties from it, at runtime, and errors won’t be generated even if the property doesn’t exist. So we could ask for myinstance.thisVariableDoentExist and no error would be thrown.

(2) Next we extend flash.utils.Proxy because we want a way to capture these undefined property requests; With flash.utils.Proxy, when such a request occurs, a method of the Proxy class called getProperty() is automatically triggered for us (there are other methods triggered by other actions, so be sure to check out the docs – this is one handy class), and this allows us to do something in response to that request.

(3) We override the getProperty() method, so that we can write code which responds to the undefined requests.

(4) One small quirk is that the getProperty() method exists inside the flash_proxy namespace; All this means for us is that we have to import flash.utils.flash_proxy (intellisense won’t pick it up, but it does exist) and use it in front of the method (much in the same way we use access modifiers like ‘public‘ and ‘private‘) – see the code for an example.

(5) Our class also needs to load in some XML (our external config file), store it, and optionally dispatch an event once the data has loaded in, which is why I also implement the IEventDispatcher interface – if you’re not familiar with implementing IEventDispacher I suggest you look it up in the docs because about half the code in this class can essentially be ignored if you don’t want to dispatch events. We can’t extend multiple classes in AS3 – we are already extending Proxy, so we have to implement IEventDispatcher rather than extend EventDispatcher in order to get event dispatching functionality.

Putting It All Together

Okay, now that we can store XML and catch undefined property requests, we can see what property is being requested and look for it inside our loaded XML file. We return the value being requested, from the XML, but it appears as if the property belongs to our class. As the name implies, we are proxying the request on to the XML.

Below is a snippet of our class. You can see that in getProperty() I use e4x to grab the value out of the saved XML file. If the XML doesn’t contain the value then our method returns an empty String (of course you can modify this how you see fit):

[as3]
package config
{
/**
* config.AppConfig.
*
* Loads &amp; stores an XML config file, and returns the data from it as if the data belonged to the class instance.
* XML data nodes must be in the form:
*
(where nodeID &amp; nodeValue represent your values).
*
* NOTE: Class is dynamic.
* Class overrides Proxy.
* Class imports &amp; uses flash_proxy namespace.
*
*/

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.utils.Proxy;
import flash.utils.flash_proxy;

public dynamic class AppConfig extends Proxy implements IEventDispatcher
{
protected var _eventDispatcher:IEventDispatcher;
protected var _data:XML;
protected var _dataLoaded:Boolean = false;
private var _urlLoader:URLLoader;

public function AppConfig()
{
_eventDispatcher = new EventDispatcher();
}

public function loadConfigFile(url:String):void
{
var request:URLRequest = new URLRequest(url);
_urlLoader = new URLLoader();
_urlLoader.addEventListener(Event.COMPLETE, onDataLoaded);
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
_urlLoader.load(request);
}

protected function onDataLoaded(event:Event):void
{
_data = XML(_urlLoader.data);
_dataLoaded = true;
removeListeners();
dispatchEvent(new Event(Event.COMPLETE));
}

override flash_proxy function getProperty(name:*):*
{
if(_data)
{
var propName:String = name.toString();
return (_data.prop.(@id == propName).@value).toString();
}
}

//…..more class stuff not shown
[/as3]

So the upshot is that we now have a class that can load in any config file (as long as the XML follows the same formatting), and this class doesn’t have to be updated if/when the XML changes. We can instantiate n instances of our class and load in n types of XML file (one for config settings, one for strings, one for whatever else we need). It’s a handy way to approach the loading of config files.

9 thoughts on “Using ‘Proxy’ For Loading & Accessing Config Files

  1. johannes

    we use a similar approach, with some differences. We allow for tokens in your config file, meaning:

    http://www.domain.com
    ${server.path}/someOther/part

    another trick i use is modifying these config files dependent on where it gets deployed (production package, QA package or on dev)
    via ant using xml-task
    this allows you replace xml tokens based on xpath.

    this obviously becomes extremely handy when building air applications as well, since you have to write the app name, version into the app-config pre compile.
    (we also generate our airbadge and the linking update.xml with this)

  2. paddy

    hi Neil,

    It would be interesting to see if having a dynamic class like this is faster than a normal class with a getProperty() helper method? i.e myInstance.getProperty(“myProperty”)

  3. paddy

    hi Neil,

    This subject has been of interest to me for a while. I can never decide which approach has the most benefits. I’ve finally got round to actually doing a little test to see which performs better giving consistent results that using a non dynamic class is a tiny bit faster:

    [MethodTest name='Dynamic Class' time=174.3 min=173 max=176 deviation=0.017 memory=664]
    [MethodTest name='Normal Class' time=161.9 min=161 max=169 deviation=0.049 memory=661]

    can send you the zip to check over if you’re interested, paddy

  4. nwebb Post author

    Paddy, another downside of this method is that (as far as I know) you can’t use an interface with a dynamic class, which of course wouldn’t be an issue for a normal class with getProperty.

  5. Mark A.

    I do not see the advantage of that solution compared to the following: After loading in the xml file you can parse it and store any attribute in a var typed Object (dynamic from the start) like this: obj[tagname]=tagvalue;

    with this solution you do not need to use e4x at everything request. Not tested but i guess this is faster. In addition to that i don’t like it to code against something that is only accessable by string because i do not get feedback at coding time. Most of the T
    time i go the extra step and setup static identifiers in my setup classes like public static var GAME_TITLE:String = “Quake 5″;
    in a class like Language so i can use it in code like : headline.text = Language.GAME_TITLE; and i get code completion.

    I Know there are cases where this solution is not applicable but in most of the cases it worse the small extra step.

  6. nwebb Post author

    Yep as you can probably tell from the above comments I’m already in agreement. I hope the post still serves as an overview of how Proxy works though :)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>