PureMVC Tutorial – Flex, PureMVC, Jabber and XIFF 3: Part 5 – Model & Proxy

Part 1 – Frameworks
Part 2 – Directory structure
Part 3 – Application and ApplicationFacade
Part 4 – Notifications, Commands & Use Cases
Part 5 – Model & Proxy
Part 6 – The Application View & Mediator
Part 7 – The Login View & Mediator
Part 8 – The Roster View & Mediator
Part 9 – The Chat View & Mediator
Conclusion, Demo & Downloads

The model is the ‘data’ of our application and the proxy is our interface onto that data.  For our particular application the model itself is basically our Jabber connection object, so the Proxy will encapsulate that and expose an interface with the following methods:

  • connect(username:String, password:String, server:String):void
  • disconnect():void
  • sendMessage(message:Message):void
  • getRosterDataProvider():ArrayCollection

As you can see, the interface is very similar to our use case and commands, and this in no coincidence; each command is going to call the relevant method in its execute method.

Create a Proxy in the model folder called XMPPProxy.as using Add->New Proxy… (if you don’t see this menu item be sure you’ve installed the PureMVC FlashDevelop templates from PureMVC: First thoughts & FlashDevelop templates correctly).

I’m just going to include the Proxy code here without much explanation as it doesn’t really do anything overly complicated (all of the hard stuff has been done for us in the XIFF library 🙂 )  Have a read through the comments of each method and everything should be clear.

   1: /*
   2: Proxy - PureMVC
   3: */
   4: package org.davekeen.xiffer.model {
   5:     import flash.events.Event;
   6:     import flash.system.Security;
   7:     import org.davekeen.xiffer.ApplicationFacade;
   8:     import org.jivesoftware.xiff.core.JID;
   9:     import org.jivesoftware.xiff.core.XMPPSocketConnection;
  10:     import org.jivesoftware.xiff.data.Message;
  11:     import org.jivesoftware.xiff.data.Presence;
  12:     import org.jivesoftware.xiff.events.*
  13:     import org.jivesoftware.xiff.im.Roster;
  14:     import org.puremvc.as3.interfaces.IProxy;
  15:     import org.puremvc.as3.patterns.proxy.Proxy;
  16:     import mx.collections.ArrayCollection;
  18:     /**
  19:      * Proxy to XMPP server
  20:      */
  21:     public class XMPPProxy extends Proxy implements IProxy {
  23:         public static const NAME:String = "XMPPProxy";
  25:         private var xmppSocketConnection:XMPPSocketConnection;
  26:         private var roster:Roster;
  28:         public function XMPPProxy(data:Object = null) {
  29:             super(NAME, data);
  31:             setupConnection();
  32:             configureListeners();
  33:         }
  35:         /**
  36:          * Create the required XMPP objects and do any configuration on them that we might require
  37:          */
  38:         private function setupConnection():void {
  39:             xmppSocketConnection = new XMPPSocketConnection();
  41:             roster = new Roster();
  42:             roster.connection = xmppSocketConnection;
  43:         }
  45:         private function configureListeners():void {
  46:             // Add event listeners related to the connection
  47:             xmppSocketConnection.addEventListener(LoginEvent.LOGIN, onLogin);
  48:             xmppSocketConnection.addEventListener(XIFFErrorEvent.XIFF_ERROR, onXiffError);
  49:             xmppSocketConnection.addEventListener(DisconnectionEvent.DISCONNECT, onDisconnect);
  51:             // Add event listeners related to messages
  52:             xmppSocketConnection.addEventListener(MessageEvent.MESSAGE, onMessage);
  54:         }
  56:         /**
  57:          * Attempt to connect to a XMPP server
  58:          * 
  59:          * @param    username
  60:          * @param    password
  61:          * @param    server
  62:          */
  63:         public function connect(username:String, password:String, server:String):void {
  64:             // Attempt to load a crossdomain permissions file
  65:             Security.loadPolicyFile(server + "/crossdomain.xml");
  67:             // Connect using standard profile
  68:             xmppSocketConnection.username = username;
  69:             xmppSocketConnection.password = password;
  70:             xmppSocketConnection.server = server;
  71:             xmppSocketConnection.connect("standard");
  72:         }
  74:         /**
  75:          * Disconnect from a XMPP server.  If not currently connected this will have no effect.
  76:          * 
  77:          */
  78:         public function disconnect():void {
  79:             xmppSocketConnection.disconnect();
  80:         }
  82:         /**
  83:          * Return the roster as a data provider
  84:          * 
  85:          * @return
  86:          */
  87:         public function getRosterDataProvider():ArrayCollection {
  88:             return roster;
  89:         }
  91:         /**
  92:          * Send a message to the server
  93:          * 
  94:          * @param    message
  95:          */
  96:         public function sendMessage(message:Message):void {
  97:             xmppSocketConnection.send(message);
  98:         }
 100:         /**
 101:          * The user has successfully logged on to the XMPP server
 102:          * 
 103:          * @param    connectionSuccessEvent
 104:          */
 105:         private function onLogin(loginEvent:LoginEvent):void {
 106:             roster.setPresence(Presence.SHOW_CHAT, "", 0);
 108:             sendNotification(ApplicationFacade.VALID_LOGIN);
 109:         }
 111:         /**
 112:          * There has been a Jabber error - most likely an incorrect username/password error
 113:          * 
 114:          * @param    xiffErrorEvent
 115:          */
 116:         private function onXiffError(xiffErrorEvent:XIFFErrorEvent):void {
 117:             if (xiffErrorEvent.errorCode == 400)
 118:                 sendNotification(ApplicationFacade.INVALID_LOGIN);
 120:         }
 122:         /**
 123:          * The user has disconnected from the XMPP server
 124:          * 
 125:          * @param    disconnectionEvent
 126:          */
 127:         private function onDisconnect(disconnectionEvent:DisconnectionEvent):void {
 128:             sendNotification(ApplicationFacade.DISCONNECT);
 129:         }
 131:         /**
 132:          * Received a message from the server
 133:          * 
 134:          * @param    messageEvent
 135:          */
 136:         private function onMessage(messageEvent:MessageEvent):void {
 137:             sendNotification(ApplicationFacade.RECEIVE_MESSAGE, messageEvent.data);
 138:         }
 140:     }
 141: }

One thing you will notice is that the proxy dispatches another few notifications that we haven’t included in our ApplicationFacade:


So lets go back to our ApplicationFacade and add them in:

   1: public static const VALID_LOGIN:String = "valid_login";
   2: public static const INVALID_LOGIN:String = "invalid_login";
   3: public static const DISCONNECT:String = "disconnect";
   4: public static const RECEIVE_MESSAGE:String = "receive_message";

The final thing we need to do is register our new Proxy with PureMVC.  We do this in StartupCommand.as using the registerProxy method:

   1: override public function execute(notification:INotification):void {
   2:     facade.registerProxy(new XMPPProxy());
   3: }

Its quite easy to forget to do this and end up with all kinds of strange errors, so be sure to remember to register any proxies you create.

We’ve finally got the bones of our application up and running so now its on to the views and mediators!

PureMVC Tutorial – Flex, PureMVC, Jabber and XIFF 3: Part 2 – Directory structure

Part 1 – Frameworks
Part 2 – Directory structure
Part 3 – Application and ApplicationFacade
Part 4 – Notifications, Commands & Use Cases
Part 5 – Model & Proxy
Part 6 – The Application View & Mediator
Part 7 – The Login View & Mediator
Part 8 – The Roster View & Mediator
Part 9 – The Chat View & Mediator
Conclusion, Demo & Downloads

We need to create a PureMVC-friendly folder structure for our application – right click on src and create org, then within that create davekeen, then within that create xiffer.  This will be the base package for our Jabber client.  Now we need folders for the various bits of our application.  Within xiffer create three folders named controller, view, model and events.  Finally within view create a folder called components.  We should have ended up with a folder structure that looks like this:


Now is a good time to explain what each folder’s contents and functions are.  If you haven’t already done so you should have a read through the PureMVC best practices and framework overview as it will make things a lot clearer.


This is the base package of our application and will contain Application.mxml (the Flex entry point) and ApplicationFacade.as (the PureMVC entry point).  The rest of the application will be contained in the other folders.


The controller package contains commands which implement individual pieces of business logic.  For our Jabber client this will be things like login, logout and send message.


The model package contains proxies which are the bits of code that do all the dirty work.  All communication between our application and the Jabber server will happen within the proxy; in fact this is the only bit of the application that will even know that a Jabber server exists.


The components packages contains our actual MXML files – the things we’ll see on the screen.  Cliff Hall has put a lot of thought into the design of PureMVC and these components know nothing about the framework or internals of our app.  When things happen they dispatch events, and they might expose public methods which the framework can invoke.


The view package contains mediators which control our components.  In some MVC frameworks this folder might contain the actual objects that are displayed (i.e. subclassing DisplayObject), but PureMVC adds an extra level of abstraction.  The mediators know about PureMVC, but the components are completely self-contained and rely on their associated mediators to do any application-wide communication.


The majority of communication within PureMVC is done using notifications, but the only exception to this is communication from components to their mediators which is done using normal AS3 events.  Its also perfectly acceptable to put this package within the view folder.

Onto part 3…

PureMVC: First thoughts & FlashDevelop templates

For those who aren’t interested in this blog and just want to get the FlashDevelop templates for PureMVC 2.0.3 you can download them here!

I’ve been meaning to have a good play with PureMVC for a while, and finally found some time a few days ago to check it out. For those who don’t know, PureMVC is one of a few Actionscript Model-View-Controller (MVC) frameworks for Actionscript. Two big established frameworks are ARP and Cairngorm (for Flex), and there are a bunch of other less well known frameworks, lots of which are available from OSFlash.

Personally I’m looking to get a few specific things out of my MVC framework:

  • Encapsulated concerns, high cohesion and loose coupling
  • Minimum configuration & ease of coding
  • Ease of maintenance

I’ll talk about each of these things separately. At this point I should point out that I have only been working with PureMVC for a little more than a day (that’s why it says first thoughts in the title), and some of what I’m saying here might be wrong! Any discussion on these points is gratefully received.

Encapsulated concerns, high cohesion and loose coupling

PureMVC takes a slightly different approach to the MVC design pattern than the official (if there is such a thing) stance, adding a bunch of extra design patterns into the mix. The View, Model and Controller are Singletons with access provided through a central Facade which is effectively the entrypoint and hub of your application. Models are then implemented as Proxies, controllers as Commands and views as Mediators. Communication between object is mostly done using PureMVC’s own Notification system rather than AS3 Events – this seems an odd design decision, but now that PureMVC is being ported to a whole host of different languages which do not support AS3 Events (Ruby, Python, HaXe, etc) this makes sense. I haven’t yet delved into the code to see if AS3 events are being used under the hood but if they are not, and if this performance boost was required, I imagine it would be fairly easy to implement. Note that AS3 events are still used on the visual side of things (i.e. between the Views and their Mediators).

Implementing the model through a proxy makes excellent sense, and makes the implementation of the model transparent to the rest of the application. All the app needs to care about is whether the call is synchronous or asynchronous and it should be possible to swap models around to your heart’s content. In fact, I’m sure it would be possible to ammend the Proxy such that all calls are treated as asynchronous giving complete transparency to the rest of the app.

Implementing controllers through commands is tried and tested, and pretty common. Its always worked fine for me. One nice touch that PureMVC adds is to allow direct mapping of Notifications->Commands with code such as:

   1: registerCommand(STARTUP, StartupCommand);

Nice and easy 🙂

The View/Mediator decision is a little more controversial, and I’ve read more than a few bloggers who find this a serious flaw in PureMVC. I can certainly see the motivation for it and in some ways its a very elegant solution, but I’ll need to try writing a medium-large size app before I can really comment. If the coder keeps it together and organises his components, mediators and composition carefully it could be that this works well. More on this in a later blog.

Minimum configuration & ease of coding

PureMVC involves a lot of typing. Creating a Mediator from scratch is a whole lot of hassle. Luckily for you FlashDevelop users I’ve updated some templates to work with PureMVC 2.0.3 (apologies to whoever wrote these in the first place – can’t find the URL, but will link as soon as I do!). Download them here and unzip to:

C:Documents and Settings<user>Local SettingsApplication DataFlashDevelopTemplatesProjectFilesAS3Project

However, even with templates taking away a lot of the setup work, there is still a lot of typing to do. Need to get a reference to a Proxy in your Command?

   1: var userProxy:UserProxy = facade.retrieveProxy(UserProxy.NAME) as UserProxy;

Ok, maybe I’m being pedantic, but when I’m writing a large RIA application I can imagine this getting very annoying. And my initial thoughts are that this seems to be a general theme throughout PureMVC; there is often a lot of work to do in order to get a simple task done. However, my feeling is that there will be a bunch of common tasks that will be able to be automated either through utility classes or through your IDE. And if the result of this extra typing is an elegantly structured and maintainable app then I guess its all worthwhile in the end 🙂

Ease of maintenance

GIGO. PureMVC goes a long way to forcing the programmer to ‘do the right thing’, but I reckon you can still end up with a mess of spaghetti if you are not careful. At this point the potential stumbling blocks seem to me to include:

  • Badly composed view and mediators.
  • Unnecessary numbers of Proxies, Commands and Mediators.
  • De-centralised logic (i.e. business logic placed in the view, which is actually possible with PureMVC)

I can easily envisage a situation where a bug arises and the developer is hard pushed to work out if it is located in the Mediator, Command or Proxy. However, I could be wrong about this and am very much looking forward to finding out myself.


Well, there isn’t one yet. I’ve a couple of weeks contractual work beginning next week where with any luck the client will be happy to have PureMVC let loose on their project so once I have some more hands-on practical experience with this framework I’ll be blogging something new. More later 🙂