PureMVC Tutorial – Flex, PureMVC, Jabber and XIFF 3: Part 8 – The Roster View & Mediator

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

By now you should be becoming a bit of an old hand at this PureMVC lark, so I’m going to be explaining stuff in a bit less detail.  If you get stuck re-read the previous sections until you have everything clear in your head.

The Roster is very simple.  We want a Flex DataGrid displaying usernames and login status and we need a ‘Start chat…’ button that opens a chat window.

In order to implement this view we’ll need a new event called ChatEvent.as.  The JID class is part of the XIFF framework and is used to identify a Jabber user.  The RosterView will only use START_CHAT, but we’ll need SEND_MESSAGE in the next and final view.

   1: package org.davekeen.xiffer.events {
   2:     import flash.events.Event;
   3:     import org.jivesoftware.xiff.core.JID;
   4:     
   5:     /**
   6:     * This event is related to the ChatViews
   7:     * 
   8:     * @author Dave Keen
   9:     */
  10:     public class ChatEvent extends Event {
  11:         
  12:         public static const START_CHAT:String = "start_chat";
  13:         public static const SEND_MESSAGE:String = "send_message";
  14:         
  15:         private var jid:JID;
  16:         private var message:String;
  17:         
  18:         public function ChatEvent(type:String, jid:JID, message:String = null, bubbles:Boolean=false, cancelable:Boolean=false) { 
  19:             super(type, bubbles, cancelable);
  20:             
  21:             this.jid = jid;
  22:             this.message = message;
  23:         } 
  24:         
  25:         public function getJID():JID {
  26:             return jid;
  27:         }
  28:         
  29:         public function getMessage():String {
  30:             return message;
  31:         }
  32:         
  33:         public override function clone():Event { 
  34:             return new ChatEvent(type, jid, message, bubbles, cancelable);
  35:         } 
  36:         
  37:     }
  38:     
  39: }

We’ll also need to define one new notification in ApplicationFacade.as called OPEN_CHAT_WINDOW:

   1: public static const OPEN_CHAT_WINDOW:String = "open_chat_window";

Next we create our RosterView.mxml file in components:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" width="100%" height="100%">
   3:     <mx:Script>
   4:         <![CDATA[
   5:         import flash.events.Event;
   6:         import mx.events.ListEvent;
   7:         import org.davekeen.xiffer.events.ChatEvent;
   8:         import org.jivesoftware.xiff.core.JID;
   9:         
  10:         private function onChatClick():void {
  11:             if (rosterGrid.selectedItem) {
  12:                 // Get the selected item and convert it to a JID
  13:                 var jid:JID = new JID(rosterGrid.selectedItem.jid);
  14:                 
  15:                 // Dispatch an event for the mediator
  16:                 dispatchEvent(new ChatEvent(ChatEvent.START_CHAT, jid));
  17:             }
  18:         }
  19:         
  20:         ]]>
  21:     </mx:Script>
  22:     <mx:TitleWindow id="titleWindow" title="Buddy list" enabled="false">
  23:         <mx:DataGrid id="rosterGrid" editable="false" width="160" height="300" showHeaders="true">
  24:             <mx:columns>
  25:                 <mx:DataGridColumn dataField="displayName" headerText="Username" />
  26:                 <mx:DataGridColumn dataField="online" width="55" headerText="Online?" />
  27:             </mx:columns>
  28:         </mx:DataGrid>
  29:         <mx:Button width="160" label="Chat..." click="onChatClick()" />
  30:     </mx:TitleWindow>
  31: </mx:Canvas>

Add this component to the display list of our top-level Application.mxml component so that the <mx:Canvas> component now reads:

   1: <mx:Canvas left="0" top="0" right="0" bottom="0">
   2:     <view:LoginView id="loginView" />
   3:     <view:RosterView y="30" id="rosterView" />
   4: </mx:Canvas>

Now we need to create RosterMediator.as in the view folder, and register it with PureMVC.  Using the rule we applied in the previous section we can see that we need to do this registration in ApplicationMediator.as:

   1: public function ApplicationMediator(viewComponent:Object) {
   2:     // pass the viewComponent to the superclass where 
   3:     // it will be stored in the inherited viewComponent property
   4:     super(NAME, viewComponent);
   5:     
   6:     facade.registerMediator(new LoginMediator(application.loginView));
   7:     facade.registerMediator(new RosterMediator(application.rosterView));
   8: }

All that is left now is to configure our mediator using the same steps as in the previous section.

1. Add listeners

RosterView.mxml dispatches only ChatEvent.START_CHAT so let’s add a listener in the constructor:

   1: public function RosterMediator(viewComponent:Object) {
   2:     // pass the viewComponent to the superclass where 
   3:     // it will be stored in the inherited viewComponent property
   4:     super(NAME, viewComponent);
   5:     
   6:     rosterView.addEventListener(ChatEvent.START_CHAT, onStartChat);
   7: }
   8:  
   9: private function onStartChat(chatEvent:ChatEvent):void { }

2. Add notifications

The Roster window need to enable and disable depending on whether or not the user is connected to a jabber server, and also needs to fill in the DataGrid with the list of buddies.  To achieve these goals the mediator will need to register an interest in ApplicationFacade.VALID_LOGIN and ApplicationFacade.DISCONNECT.

   1: override public function listNotificationInterests():Array {
   2:     return [
   3:             ApplicationFacade.VALID_LOGIN,
   4:             ApplicationFacade.DISCONNECT
   5:             ];
   6: }

And here are the clauses for the switch statement:

   1: override public function handleNotification(note:INotification):void {
   2:     switch (note.getName()) {
   3:         case ApplicationFacade.VALID_LOGIN:
   4:              break;
   5:         case ApplicationFacade.DISCONNECT:
   6:             break;
   7:         default:
   8:             break;        
   9:     }
  10: }

3. Fill in the event listeners and switch clauses

Firstly we’ll fill in the onStartChat event listener.  This will very simply send an ApplicationFacade.OPEN_CHAT_WINDOW with the JID as the argument.  Although we could have passed the ChatEvent itself as a parameter in this case there is no need to use a value object as to open a chat window we only require a single item of information – the JID.

   1: private function onStartChat(chatEvent:ChatEvent):void {
   2:     sendNotification(ApplicationFacade.OPEN_CHAT_WINDOW, chatEvent.getJID());
   3: }

You’ll notice that the ApplicationFacade.OPEN_CHAT_WINDOW notification is not mapped to a command – this is because the only responder to the notification will be the ChatMediator that we are about to create in the next section so there is no need to have a command.  However, one of the beautiful things about PureMVC is that if it turned out later in the development that this notification needed to affect the model in some way we could implement this merely by adding a new command and registering it, and there will be no need to make any changes to the rest of the application.

Compile and run the application and enjoy the working buddy list!  Only one view left to go…

PureMVC Tutorial – Flex, PureMVC, Jabber and XIFF 3: Part 1 – Frameworks

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

Now that we’ve got a basic FlashDevelop project setup we can install the frameworks we’ll be using.

PureMVC

Download the PureMVC framework from here. Put this into a directory somewhere on your machine and add this to the FlashDevelop project classpath like so:

  1. Right click on ‘XIFFer’ and select Properties…
  2. Go to the Classpaths tab
  3. Click Add Classpath… and in the directory selector choose the PureMVC src folder.

XIFF

XIFF is an excellent Actionscript XMPP (Jabber) framework that we’ll be using to take care of the internals of Jabber communication. Its been around since Actionscript 2 but has recently been ported to Actionscript 3 (albeit in beta form). Download it here, put it into a directory and add the classpath as above.

As XIFF is currently in beta you’ll need to make a small change in order to get it to play nice with ejabberd – a common Jabber server written in Erlang. Research tells me that this is actually a problem with ejabberd’s implementation rather than XIFF’s, but whatever the issue might be this will fix it 🙂

  1. Open org.jivesoftware.xiff.core.XMPPSocketConnection
  2. Goto line 108
  3. Remove the version=”1.0″ / so that the line now reads:

openingStreamTag = “<?xml version=”1.0″?><stream:stream to=”” + server + “” xmlns=”jabber:client” xmlns:stream=”http://etherx.jabber.org/streams”>”;

Now we’re all sorted with the bits we require and its time to set up our directories and packages.