PEP(Personal Eventing Protocol) with Smack

Personal Eventing Protocol (aka PEP) is a really nice pubsub feature on the Jabber platform. It allows you to publish information regarding yourself to your friends in your roster, like what Facebook. The XMPP community calls this rich presence.

I’ve been wanting to play with this feature so I started a little project to look into this. I’ll publish what games I’m playing using a yet unapproved XMPP specs call User Gaming (XEP-196). There are really 2 pieces to this little exercise:

  1. The low level bit which includes
    • Setting up data in the correct XML document/fragment and then send this out via Smack
    • Configuring Smack with the correct parser for your XML document; this is call a provider in Smack terminology. Parsing is required on the recipient side
  2. Using the high level Smack API to publish and receive incoming PEP messages

This will be a 3 part blog with this part focusing on creating the PEP item and sending it.

Setup

Get the latest copy of Smack from the repository. You need to get the source because we will need to make 2 small changes to PEPItem.java. Add the keyword public to lines 36, 37 like so

public abstract String getNode();
public abstract String getItemDetailsXML();

then recompile and use the new smackx.jar.

Creating PEP Payload for Publishing

To publish a PEP item, we need to know the structure of the XML document; here is how a typical out going (viz. publish) looks like

<pubsub xmlns=”http://jabber.org/protocol/pubsub”&gt;
   <publish node=”urn:xmpp:gaming:0″>
      <item id=”m3GYKa7jNiXf800pJ8cr”>
         <game xmlns=”urn:xmpp:gaming:0″>
            <character_name>Sentor</character_name>
                …
        </game>

      </item>
   </publish>
</pubsub>

Our responsibility is to generate the bits in red and green. The <game> is User Gaming and <item> is the envelope. The following code snippet shows how we use JAXB to generate the <game> fragment:

@XmlRootElement(name=Game.ELEMENT_NAME, namespace=Game.NAMESPACE)
public class Game {
   public static final String ELEMENT_NAME = “game”;
   public static final String NAMESPACE = “urn:xmpp:gaming:0″;
   private String characterName;   
      …
   @XmlElement(name=”character_name”, namespace=Game.NAMESPACE)
   public String getCharacterName() {
      return characterName;
   }
   public void setCharacterName(String characterName) {
      this.characterName = characterName;
   }
      …
   public String toXML() {
      String result = “<game/>”;
      try {
         JAXBContext context = JAXBContext.newInstance(Game.class);
         Marshaller gameMarshaller = context.createMarshaller();
         //Do not generate the XML declaration
         gameMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
         StringWriter sw = new StringWriter();
         gameMarshaller.marshal(this, sw);
         result = sw.toString();
      } catch (Exception e) {
         Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, “toXML()”, e);
      }
      return (result);
   }
      …
}

I’ve used toXML() instead of toString() to produce the XML fragment; this is in keeping with the conventions used in the Smack library.

Next up, we need to create the <item> wrapper. The following code snippet shows this:

public class GameItem extends PEPItem {
   private final Game game = null;
   private final String id;
   public GameItem(String i, Game g) {
      super(i);
      id = i;
      game = g;
   }
   public String getId() {
      return (id);
   }
   @Override
   public String getNode() {
      return (Constants.Game.NAMESPACE);
   }   
   @Override
   public String getItemDetailsXML() {      
      return ((game != null)? game.toXML(): “<game/>”);
   }

Some salient points about GameItem class

  1. You MUST extend PEPItem. The reason is that when you publish a PEP item, the publish() will only publish PEPItem type object. That is why you must also make the modification to PEPItem.java file (above), otherwise you would not be able to publish anything!
  2. For some strange reason, PEPItem does not allow you to get access to the id. On some protocol like user gaming, you use the same id to cancel a previous item. So its a good idea to add a getId(). Smack also has a handy utility to generate id strings. See StringUtils.randomString().
  3. getNode() method returns the name of the node. In PEP, this is typically the same as the namespace of the object. See One Node Per Namespace.
  4. getItemDetailsXML() returns <game> document.

Here is a how everything fits together

<pubsub xmlns=”http://jabber.org/protocol/pubsub”&gt;
   <publish node=”urn:xmpp:gaming:0“>  <—- getNode()
      <item id=”m3GYKa7jNiXf800pJ8cr“> <—- id from GameItem/PEPItem
         <game xmlns=”urn:xmpp:gaming:0″>
            <character_name>Sentor</character_name> <— everything in blue from getItemDetailsXML()

                …
        </game>

     
</item>
   </publish>
</pubsub>

Publishing

To publish a PEP item, create an instance of PEPManager, and invoke publish().

//Create an instance of PEPManager from a XMPPConnection
XMPPConnection conn = …
PEPManager mgr = new PEPManager(conn);

//Create an instance of Game and GameItem
Game game = new Game();
game.setCharacterName(“Sentor”);
game.set…

GameItem item = new GameItem(StringUtils.randomString(7), game);

//Now publish it
mgr.publish(item);

My next blog will look into receiving PEP messages. Happy hacking.

Follow

Get every new post delivered to your Inbox.