Flex and Jabber, a practical approach

The widely adopted open protocol for instant messaging XMPP (also called Jabber) is a de facto standard used in various instant messaging systems. The aim of this article is to show how quick and easy it is to create a real time application using this protocol that relies on a restful architecture.

In order to start playing with Flex and the XMPP protocol you have to select the server you prefer and install it.
My choice is Open Fire (http://www.igniterealtime.org/), and the main reasons for this choice are:

•    It’s fully compliant to the standards
•    It’s very easy to install
•    It can work with several databases in addition to the built-in one (it supports MySQL, PostgressSQL, Oracle, SQLServer and IBM DB2)
•    It can interact with OpenLDAP and / or Active Directory
•    It can track all the IM traffic and store it as XML files
•    It has a great log panel
•    It can easily administer chats and rooms
•    Options allow control over room moderation, maximum occupancy, presence information, and more
•    There is a good ActionScript library that can interact with Open Fire

In order to setup your environment you have to follow the wizard provided with the Open Fire installer (I suggest you keep in place the built-in database and the default settings) and then you can login on your localhost to the administrative console.
Create a new Flex project with you favorite IDE and add the XIFF library (http://www.igniterealtime.org/downloads/download-landing.jsp?file=xiff/xiff_3_0_0-beta1.zip) to the project.
As you can see the XIFF library is very rich and it supports more or less all the features of the XMPP protocol.
In a project I worked on, some of the junior developers’ first reactions to the XIFF library and to the restful architecture you can get with the XMPP protocol was to interrupt development in order to study all the protocols and servers we were using for the project.
This reaction led me to write down a “driver” that can deal with the XIFF library and the XMPP protocol in order to avoid any panic in the development team and to prevent people from wasting time on a concept that was beyond the scope of the project itself.
Let’s think of this driver as a layer component that hides the complexity and the richness of the XIFF library to make things easier.
In order to show you how it works I created a very simple application with the following features:

•    Anonymous and registered login
•    Chat services discovery
•    Personal chat room creation and destruction
•    Room user list
•    Friends request support (accept and deny)
•    Messages broadcast

The user interface of this demo is quite simple and easy to understand, take a look to it on-line.

The driver is made up of several classes, events and value objects but it’s really simple to use because the two most important files you have to know are two interfaces and a class used to discover the available services

•    IRealTime
•    ServiceBrowser
•    IChatControls

The first one is responsible for the connection to the XMPP server and for the initialization of communication between client and server.
Available methods are:

•    init(port:int, resource:String):void;
// initialize the connection over a specific port and
// send the appropriate resource type the XIFF library
•    connect(domain:String, anonymous:Boolean, user:User = null):void;
// connect to a specific domain using anonymous login or an User object that is made up by username and password
•    disconnect():void;
// self explanatory
•    keepAlive(live:Boolean):void;
// keep the connection with the server alive also
// after long period of inactivity
•    connection():XMPPConnection
// return the established connection instance
•    startRealtime(room:OpenFireRoomEssentials):void
// create or join an existing room

The class that implements this interface is the RealtimeManager, each instance of which can dispatch some events. To keep things simple, the class actually wraps some events defined in the XIFF library using a custom event class. Dispatched events are:

•    UserAccessEvent.CONNECTED
•    UserAccessEvent.LOGIN
•    UserAccessEvent.LOGOUT

The ServiceBrowser class is responsible for discovering chat services, the rooms defined on each service and the details of each room.
All information is made available through a series of events. Events dispatched from the ServiceBrowser class are:

•    AvailableRoomsEvent
•    AvailableServicesEvents
•    DetailRoomEvent

Each event provides information about the services available on the server, the rooms that are active on a specific service and the detail of a specific room (needed in order to launch the realTime method).

The last interface you should know about is the IChatControls. Methods defined by this interface are:

•    updatePresence( show:String, status:String ):void;
// send to the roster the user status
•    joinRoom(room:Room, jid:UnescapedJID):void;
// join a specific room and using the JID initialize the loading of the roster
// and the set up of the room
•    isValidJID( jid:UnescapedJID):Boolean;
// check if the JID is valid or not
•    sendMessage(message:String = null, html:String = null):void;
// send a message in the joined room, it supports both html and plain text
•    sendMessageTo(text:String, tojid:EscapedJID):void;
// send a message to a specific user
•    createRoom(room:Room):void;
// create a personal room
•    destroyRoom(room:Room, reason:String = null):void;
// destroy the personal room the user has created
•    leave():void;
// allow the user to leave the current room
•    invite(userId:EscapedJID):void;
// invite a specific to the personal room
•    addFriend(user:RoomOccupant):void;
// add an user as a friends to the user roster
•    removeFriend( user:RosterItemVO ):void;
// remove a specific user from the friends list
•    grantSubscription(id:UnescapedJID, status:Boolean = true):void;
// grant to an user the request of subscription to the friends list
•    denySubscription(id:UnescapedJID):void;
// deny the subscription to a specific user
•    personalRoom():Room;
// recover the personal room created by the user
•    dispose();
// free the memory and the event listener

The class that implements this interface is the ChatManager, which can dispatch events in order to distribute the data recovered and managed internally, and the events are:

•    FriendsInvitation.FRIEND_REQUEST_INCOMING
•    FriendsEvent.LIST_RECOVERED
•    FriendsInvitation.FRIEND_REQUEST_DENIED
•    FriendsInvitation.FRIEND_REQUEST_ACCETPED
•    FriendsInvitation.FRIEND_LIST_REMOVED
•    ChatMessageEvent.GROUP_MESSAGE
•    PersonalRoomEvent.ROOM_DESTROYED
•    RoomUsersEvent.JOINED
•    RoomUsersEvent.LEFT
•    RoomUsersEvent.PRESENCE

As in the case of the RealtimeManager class, these events wrap some events defined in the XIFF library in order to keep things a little bit simpler and to prevent concepts like rosters, persistent rooms, etc. from becoming a problem during development.

Now you know everything you need to start using this driver that keeps things simpler and easier to understand.
Come back for one moment to the image that shows the user interface of our application, and let’s examine what we have to do to make it work.
In order to set up our application we have to put in place the following workflow:

•    Create an instance of the IChatControls interface implementer
•    Create an instance of the IRealTime interface implementer
•    Define the listeners for the UserAccessEvent.LOGIN event
•    Create an instance of the ServiceBrowser class in the UserAccessEvent.LOGIN handler and recover the services available through the currentServices() method
•    Handle through the user interface the data propagated through the events of the ServiceBrowser class
•    Invoke the joinRoom() method of the IChatControls interface implementer

Create a new Flex application, add the XIFF library to your libs folder and grab the source code of the driver you can get here www.mxml.it/tutorials/xiffdriver.zip.
First of all, define the user interface in the main MXML file of the project

Next, open a script tag and define the constants used inside the application:

The first one represents the address of your Open Fire installation, the second is the name of the service on which personal rooms will be created and the third is the suffix that will be added to all personal room names.

Create the class members you need to store an instance of the 3 main actors of the application

and the class members needed to store the details of the room the user is going to join, the unique identifier provided by the XMPP server (inject this in the chat manager to perform all operations related to a user) and the unique identifier of the user that performs a friend request

In order to start playing with the driver classes, perform the override of the childrenCreated method and define here both instances of the IRealTime implementer and of the IChatControls implement and the event handlers needed to manage the data propagated from these classes

Let’s start exploring one by one all the methods registered as listeners in the childrenCreated method.
The onRoomJoin listener handles the UI, enabling it after user login

The onRoomLeft method handles the UI, disabling controls after the user has left a room

The onRoomPresence method is the handler used to get the status of a specific user, in this sample it simply shows some logs, in a real implementation this is the method in which you have to update the status of a specific user in the room user list

The onFriendsList method is responsible for populating the list of friends (i.e. the roster)

the onGroupMessageReceived method handles all messages sent against the ‘general’ chat

The onFriendsNotSupported method catches the notification that anonymous users cannot add another user to their friends list

The onFriendsRequest method handles friend requests that come from another user, storing that user’s unique identifier and updating the user interface controls

The onFriendsRequestDenied method notifies the application that a friend request has been denied by another user

The onFriendsRequestAccepted method notifies the application that a friend request has been accepted

The onFriendsListRemoved method handles the event that notifies the application that a user has been removed from the friends list

The onPersonalRoomCreated method simply gives an Alert to notify the application that the personal room has been created

The onPersonalRoomExists method notifies the user that his personal room already exists and that another one cannot be created (this is not a limitation of XMPP but only a feature of the driver that doesn’t allow more than one personal room per user)

The onPersonalRoomDestroyed method handles notifications that the personal room a user joined has been destroyed

The onOpenFireError method handles all errors; in this sample implementation it handles only the 401 error code that means that a registered user has inserted wrong username and password

The on method handles anonymous or registered logins and initializes the ServiceBrowser instance and all the listeners needed to recover the information from this class. It’s important to note here that the realtimeManager instance is finally connected, that the keepAlive property is set to true and that the ServiceBrowser instance uses the connection to the server to start exploring available services

The listeners registered to the events dispatched from the ServiceBrowser are those that populate the controls of the user interface (i.e. the list of services and available rooms) and that store information about the room the user is going to join

All the building blocks needed to handle the real time communication provided through XMPP are now in place. The following code list includes all the methods called from the user interface and it’s self-explanatory: you will now be able to run the application against your Open Fire installation

Conclusion
The real time applications are really engaging, both for the end user and for a developer. Sometimes people can be afraid of the potential difficulties in this kind of application but, as you have seen in this article, you don’t have to be a rocket scientist to be able to start playing with it.
The XMPP standard is not the only one available for the Flash Platform; the great advantage that comes with this standard is that you can handle several client side applications (developed with different technologies) with the same back end logic.

Comments

comments

3 Responses to “Flex and Jabber, a practical approach”
  1. Bruno Lemos May 14, 2010
  2. forex robot May 16, 2010
  3. dev June 2, 2010

Leave a Reply

Your email address will not be published.


*