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!