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

Introduction
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;
  17:  
  18:     /**
  19:      * Proxy to XMPP server
  20:      */
  21:     public class XMPPProxy extends Proxy implements IProxy {
  22:         
  23:         public static const NAME:String = "XMPPProxy";
  24:         
  25:         private var xmppSocketConnection:XMPPSocketConnection;
  26:         private var roster:Roster;
  27:  
  28:         public function XMPPProxy(data:Object = null) {
  29:             super(NAME, data);
  30:             
  31:             setupConnection();
  32:             configureListeners();
  33:         }
  34:         
  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();
  40:             
  41:             roster = new Roster();
  42:             roster.connection = xmppSocketConnection;
  43:         }
  44:         
  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);
  50:             
  51:             // Add event listeners related to messages
  52:             xmppSocketConnection.addEventListener(MessageEvent.MESSAGE, onMessage);
  53:             
  54:         }
  55:         
  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");
  66:             
  67:             // Connect using standard profile
  68:             xmppSocketConnection.username = username;
  69:             xmppSocketConnection.password = password;
  70:             xmppSocketConnection.server = server;
  71:             xmppSocketConnection.connect("standard");
  72:         }
  73:         
  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:         }
  81:         
  82:         /**
  83:          * Return the roster as a data provider
  84:          * 
  85:          * @return
  86:          */
  87:         public function getRosterDataProvider():ArrayCollection {
  88:             return roster;
  89:         }
  90:         
  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:         }
  99:         
 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);
 107:             
 108:             sendNotification(ApplicationFacade.VALID_LOGIN);
 109:         }
 110:         
 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);
 119:             
 120:         }
 121:         
 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:         }
 130:         
 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:         }
 139:         
 140:     }
 141: }

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

  • VALID_LOGIN
  • INVALID_LOGIN
  • RECEIVE_MESSAGE
  • DISCONNECT

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!