As I mentioned in an earlier post, I was working on building a chat room using XMPP (Jabber) and the XIFF AS3 API.
If you aren’t sure how to get started with XMPP and XIFF, make sure to check out that post to get you up and running.
Once I had successfully worked out using XIFF to connect with XMPP and pass data back and forth between the server and the client, I soon realized that I wanted to associate custom data with each user in the chat rooms.
The core protocol used in XMPP to express a user’s current network availability (offline or online, etc) is Presence.
On IM, you know when your buddies come online and become unavailable, etc because you subscribe to their presence.
The user’s presence is also sent to a chat room when he/she joins the room.
The default presence data typically only incorporates information about the user’s status (away, busy, available, etc).
The issue that I soon ran into with my chat rooms, was that our site already had a large collection of users with data associated with each user (id, username, picture, etc) and I wanted to associate this data with the chat users without duplicating the data.
The best place seemed to be their presence since its already linked directly with each user. The only issue I had was figuring out how to do that.
As I soon realized, the XMPP spec is extremely extensible and well thought through and XIFF has tried to manage this extensibility in its library as well.
In XIFF, extensions can be added to any XMPPStanza
that is sent to the XMPP server.
By default, there are three core XMPP stanzas, IQ
, Message
and Presence
.
Each of these stanza classes has an addExtension()
method.
What I needed to do was write a custom extension class that I could pass into the Presence’s addExtension()
method.
Digging in to the code, all XIFF extensions need to extend the Extension
class and implement IExtension
and ISerializable
.
To implement IExtension
, you will need to add getNS()
and getElementName()
methods.
getNS()
will return the custom unique namespace that you will need to create and associate with this extension.
eg: http://yourdomain.com/extensionname
getElementName()
will return the base XML element name to associate with this extension.
eg: extension_name
To implement ISerializable
, you will need to add serialize()
and deserialize()
methods.
serialize()
will convert the typed extension into XML data to be passed to the server while deserialize()
will do the opposite and convert the received XML data into the typed extension.
For more detailed information on this, make sure to look at some of the existing extensions in XIFF’s library.
Once the class is complete, you will need to register the extension with XIFF. This registration process informs XIFF of the particular extension so that it knows how to handle it when it is received over the network.
This can be done by calling ExtensionClassRegistry.register( CustomExtension )
anytime before you try to pass the extension over XMPP.
Most extensions provide a static enable()
method with the above code in it to handle this registration process.
At this point, you can create an instance of any of the core XMPP stanzas (IQ, Message, or Presence) and an instance of your new extension and then use the addExtension()
method of the core stanza to pass in your extension.
The last step is to call the send()
method on your XMPP connection passing in the XMPP stanza.
To finish up my particular example, I created a custom user extension that had the user’s id, name, picture, etc and attached it to the user’s presence.
This as mentioned above could be passed with the send method on the XMPP connection and anyone subscribed to my user’s presence would receive the custom extension as well.
One thing that I wanted to do was join a chat room and have this custom data associated with the presence information of all of the existing users in the room that gets broadcast out.
It took me a little bit to realize that the Room class has a feature for this already. Like I said, XMPP has thought of everything already.
When you join a chat room, you call the Room’s join()
method and the second parameter allows you to add an array of Presence extensions. Just instantiate your custom Presence extension and wrap it in an array and pass it into the join()
call.
Hopefully this helps out others that got stuck on sending custom data over XMPP with XIFF.
Let me know if you have any questions or want any other XIFF/XMPP tutorials.
Wow. All of my best compliments for your write-up. The XIFF project is really an amazing library, but it lacks of enough people talking about it. Soon I will finish my project with XIFF. I did have few issues finding out things by myself, especially since I am not a programmer (I am a frontend developer).
Although I succeeded to work out user self-registration, room creation/configuration, and the presence, even though I DID fail trying to achieve what you did.
Is there any way you could share your extention code with us? If not, I’ll understand. Anyhow, great work! Keep it up.
Hey Gianluca,
I appreciate the kind words!
Unfortunately, the extension that I wrote is tied very tightly to my company’s chat rooms so I can’t share the code.
But if you have any specific questions, ask them here and I’ll respond as best I can.
Hi,
I have a single problem, when I connect to server chat, after 6 or 7 minutes, the chat is disconnect from server and I don’t know why. Do someone have the solution?
HI Mark,
This is very useful post. Actually I am working on XMPP, I have a doubt. I need to pass some data to my roster (company, userEmail etc.). So I created a custom Extension.
package net.firstcourt.Extensions
{
import flash.xml.XMLNode;
import net.firstcourt.GlobalConst;
import org.jivesoftware.xiff.data.Extension;
import org.jivesoftware.xiff.data.ExtensionClassRegistry;
import org.jivesoftware.xiff.data.IExtension;
import org.jivesoftware.xiff.data.ISerializable;
public class UserExtension extends Extension implements IExtension, ISerializable
{
public static var NS:String = GlobalConst.SERVER + “/UserExtension”;
public static var ELEMENT:String = “userData”;
public var companyName:String;
private var myNode:XMLNode;
public function UserExtension( parent:XMLNode=null )
{
super( parent );
myNode = parent;
//myNode = new XMLNode(1, ‘company’);
//myNode.nodeValue = “myCom”;
}
public function getNS():String
{
return NS;
}
public function getElementName():String
{
return ELEMENT;
}
public function serialize( parentNode:XMLNode ):Boolean
{
parentNode.appendChild(myNode);
return true;
}
public function deserialize( node:XMLNode ):Boolean
{
setNode(node);
var children:Array = getNode().childNodes;
for( var i:String in children ) {
switch( children[i].nodeName )
{
case “company”:
companyName = children[i];
break;
}
}
return true;
}
public static function enable():void
{
ExtensionClassRegistry.register(UserExtension);
}
}
}
and I tried to connect with room
var myNode:XMLNode = new XMLNode(1, ‘company’);
myNode.nodeValue = “myCom”;
var userExtension:UserExtension = new UserExtension(myNode);
var message:Message = new Message();
message.addExtension(userExtension);
xmppSocketConnection.send(message);
var joined:Boolean = room.join(false,[userExtension]);
is this right?
from where I can get the company?
please help me.
Thanks
Roy
Hi Mark! Thank you for your good topic.
Can you write some your UserExtension class code?
And code for use this class in project?
Thank you.
Hi,
Nice topic. Very few people are working on XIFF
a) I want to populate all the groups on openfire 3.7 server from XIFF……how can i do that? the groups are not shared……RosterGroup is giving only groups to which current user is registered.
b) How to implement searching a user based on his name…..with XIFF…i have been trying Search Extension but no success……can u help please…