Receiving PEP Broadcast
August 31, 2010 8 Comments
In my last blog, I talk about PEP and how you can publish your own PEP events with
Smack. In this blog I will talk about how to hand incoming PEP
messages. First we look at how a PEP packet looks like.
<event xmlns=”http://jabber.org/protocol/pubsub#event”>
<items node=”urn:xmpp:gaming:0″>
<item id=”L5xpMkzWopMPK2AtuBUj”>
<game xmlns=”urn:xmpp:gaming:0″>
<character_name>Sentor</character_name>
<character_profile>http://wow.example.com/profile.html?123456</character_profile>
<level>66</level>
<name>Worlds of Warefare</name>
<server_address>wow6.example.com</server_address>
<server_name>WOW Example</server_name>
<uri>http://wow.example.com</uri>
</game>
</item>
</items>
</event>
The message that we are interested in is in orange. We need to do 2 things to get to this part of the message
- Write a parser or provider for <game>. The parser will convert the XML fragment to Game object (see last weeks blog).
- Register the provider with Smack’s provider framework so that our provider gets call whenever there is a <game> tag. (actually its not like that but its easier to think of it this way…)
Writing a Provider
A provider is basically a parser for the bits in orange and it returns a GameItems object. Here is how our GameProvider looks like
public class GameProvider implements PacketExtensionProvider {
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
boolean stop = false;
int evtType;
String n;
String id = null;
Game game = new Game();
while (!stop) {
evtType = parser.next();
n = parser.getName();
switch (evtType) {
case XmlPullParser.START_TAG:
if (“item”.equals(n))
id = parser.getAttributeValue(“”, “id”);
else if (“character_name”.equals(n))
game.setCharacterName(text(parser));
else if (“character_profile”.equals(n))
game.setCharacterProfile(new URI(text(parser)));
…
break;
case XmlPullParser.END_TAG:
//Stop parsing when we hit </item>
stop = “item”.equals(n);
break;
}
}
return (new GameItems(new GameItem(id, game));
}
}
Things to note about
- A provider must implement the PacketExtensionProvider interface which has only one method, parseExtension()
- Your parser is responsible for parsing all XMLs between the opening and closing <item> tag.
- Don’t forget to get the id from the <item> tag
- Once you are done, wrap the Game object in a GameItem and GameItems object.
What is the GameItems object? GameItems is responsible for wrapping our Game object inside an <event> viz. the blue bits in the XML fragment at the start of this blog. Furthermore GameItems must extend PEPEvent class. Here is an implementation
public class GameItems extends PEPEvent {
private final GamePEPItem item;
public GameItems(GamePEPItem i) {
item = i;
}
public GamePEPItem getGameItem() {
return(item);
}
@Override
public String getNamespace() {
return (“http://jabber.org/protocol/pubsub#event”);
}
public String getNode() {
return (“urn:xmpp:gaming:0″);
}
public String getItemDetailsXML() {
return (item.toXML());
}
@Override
public String toXML() {
StringBuilder sb = new StringBuilder(“<event xmlns=\”");
sb.append(getNamespace()).append(“\”><items node=\”");
sb.append(getNode()).append(“\”>”);
sb.append(getItemDetailsXML());
sb.append(“</items></event>”);
return (sb.toString());
}
}
I know it is a bit confusing with layers of objects, hopefully the following illustration will help clarify this
<event xmlns=”http://jabber.org/protocol/pubsub#event”> <– GameItems extends PEPEvent
<items node=”urn:xmpp:gaming:0″> <– generated from GameItems
<item id=”L5xpMkzWopMPK2AtuBUj”> <– GameItem extends PEPItem
<game xmlns=”urn:xmpp:gaming:0″> <– Game
…
</game>
</item>
</items>
</event>
Registering and Receiving PEP Events
In order to receive PEP messages, we must register our interest by
providing a provider (parser) and the namespace associated with the
provider. Here is a code snippet to show how this is done
PEPProvider prov = new PEPProvider();
prov.registerPEPParserExtension(“urn:xmpp:gaming:0″, new GameProvider());
ProviderManager.getInstance().addExtensionProvider(“event”, “http://jabber.org/protocol/pubsub#event”, prov);
PEPProvider is part of the PEP framework that allows you to indicate you interest in some or all PEP objects. Line 2 associates User Gaming namespace with our provider; you can register your interest in more that one namespace. The next step is to add the PEPProvider
to the overall Smack provider framework. Here the registration is very
specific, boilerplate in fact; you basically tell Smack that your
instance PEPProvider are taking over control of parsing any <event> tag that is in http://jabber.org/protocol/pubsub#event namespace
(line 3). (Note: I’m not sure what the ramifications are if there are
other providers that are also interested in the same namespace.)
The final piece of code snippets show how to add listeners (implements PEPListener).
XMPPConnection conn = … //Create an instance of XMPPConnection
PEPManager pepMgr = new PEPManager(conn);
pepMgr.addPEPListener(this); //this being PEPListener
…
public void eventReceived(String from, PEPEvent pEvt) {
//Cast it to GameItems object. pEvt is return from GameProvider
GameItems items = (GameItems) pEvt;
Game game = items.getGameItem().getGame();
…
That’s it! Feebacks and happy hacking!
Hey there,
I have read your XMPP PEP blogs posts regarding pub/sub, http://oneminutedistraction.wordpress.com/tag/java-xmpp-jabber-smack-pep-xep163-196-user-gaming/.
I have tried to implement the ideas in a proof of concept command line application. I do not seem to be catching any PEPEvents though and I am wondering if there is anything you might point me to to assist? I realize this is a bit vague without source code, I would be happy to send you some if you are interested and if that would help.
Thanks
Brett Delia
Brett, if you are using Smack, have you tried turning on debugging to see if the stanzas are coming back?
My source code for XMPP user gaming can be found here http://kenai.com/projects/jabberwocky. The source code is under XMPPUserGaming. I’ve written this as a plugin for Spark which you can download from the Download area. The XMPPUserGaming is separated into 2 main packages, specific to Spark and XMPP user gaming which is more generic. HTH
Thanks for the reply. First, your blog posts on this subject are what got us working, we really appreciate your insights and willingness to document your experiences.
I will definitely go through your source to see how you put it all together to verify we have everything wired up correctly. We ended up getting it to work finally, we had some initial issues with the fact that we needed to define two separate parsers (providers) and were initializing them incorrectly at first. We assumed, through lack of documentation, that we would need to create two distinct providers. Turns out you just need to register the PEP Parser Extention for each provider on the same Provider. That got use working.
Original code:
PEPProvider lineItemProv = new PEPProvider();
prov.registerPEPParserExtension(“urn:xmpp:lineitembom:0″, new PepMessageProvider());
PEPProvider visiBomProv = new PEPProvider();
prov.registerPEPParserExtension(“urn:xmpp:visibom:0″, new PepMessageProvider());
ProviderManager.getInstance().addExtensionProvider(“event”, “http://jabber.org/protocol/pubsub#event”, lineItemProv );
ProviderManager.getInstance().addExtensionProvider(“event”, “http://jabber.org/protocol/pubsub#event”, visiBomProv );
Code that works:
PEPProvider bomProv = new PEPProvider();
prov.registerPEPParserExtension(“urn:xmpp:visibom:0″, new PEPVisiBOMMessageProvider());
bomProv .registerPEPParserExtension(“urn:xmpp:lineitems:0″, new PepMessageProvider());
ProviderManager.getInstance().addExtensionProvider(“event”, “http://jabber.org/protocol/pubsub#event”, bomProv );
That is how I did it as well.
I can’t seem to get to the source. The repository seems empty, though it could be that I do not understand how to use Kenai. I put this into my browser after I logged in: https://hg.kenai.com/hg/jabberwocky~source but see no source tree.
Let me go check. I understand that kenai.com is undergoing some upgrades. Check back in a few days. Otherwise let me know and I’ll send you the source.
Reference: Registering and Receiving PEP Events:
(line 3). (Note: I’m not sure what the ramifications are if there are
other providers that are also interested in the same namespace.)
Within the basic PubSubManager (and I assume operation of PEP is similar) the first programmatic entity to ‘register’ to a namespace get’s the notification – the others are never registered in the Map.
Pingback: asmack – receiving custom XML messages || | PHP Developer Resource