Screencast: Are you there?

In this screencast we will show how to use @Presence to allow a XMPP external component to respond to subscription and probe messages. This is a continuation of our series of tutorial on developing CustomerQuery component with Vorpal framework.

The source thaw was developed in the screencast is availble here.

Till next time

Hello?

In XMPP, presence allows a person/bot/service to tell others about its availability. The latest release of Vorpal now supports presence; major annotations include the followin

  • @Presence – top level annotation to denote a class is a presence message handler
  • @PresenceType – type of the presence packet; see this
  • @Priority – priority of presence packet
  • @Show – availability. See this
  • @Status – the status of the presence packet

Lets see how we handle presence from an example. Remeber query@customer.batcomputer from the service discovery blog? Let say that after we have discovered query@customer.batcomputer, the user wants to add query to his/her roster. The following are the series of message exchanges between the user and the Customer Service.

The user sends a subscribe message, indicating that the user wants to receive query’s presence info

<presence to=”query@customer.batcomputer” from=”…” type=”subscribe“/>

If query@customer.batcomputer decides to accept the subscription, it’ll return a presence message with subscribed

<presence to=”fred@batcomputer/pidgin” … type=”subscribed“/>

Note: In most cases, there is also a reverse subscription send out viz. query@customer.batcomputer will also send a subscribe to fred@batcomputer. However in this use case query@customer.batcomputer is not interesed in fred@batcomputer‘s availability.

Once query has accepted the presence subscription of fred, the next message that query is going to get is most likely to be a probe message viz. enquiring about the presence status

<presence to=”query@customer.batcomputer” … type=”probe“/>

query can reply in the following way

<presence to=”fred@batcomputer/pidgin” …>
   <show>chat</show>
   <status>Available for customer enquiry</status>
   <priority>5</priority>
</presence>

assuming it is available.

We will now implement the above set of interactions with Vorpal.

@RequestScoped
@Presence
@To(“query@{__subdomain__}”)
public class PresenceHandler {
   //Method to handle subscription
   @PresenceType(type=org.xmpp.packet.Presence.Type.subscribe)
   public Object handleSubscription() {
      return (org.xmpp.packet.Presence.Type.subscribed);
   }
   …
}

  • Firstly presence handlers must be annnotated with @Presence annotation.
  • The @To is really optional; in here we are really particular in that we only want to entertain subscription request to query@customer.batcomputer.
  • Another point here is the use of @PresenceType to discriminate the packet; as you can see from the example above, when there is a subscription request handleSubscription() will fire and reply with a subscribed.

After accepting the subscription, we will now need to handle probe messages. The following handler shows how this is done

   @PresenceType(type=org.xmpp.packet.Presence.probe)
   public List<Object> handleProbe() {
      List<Object> result = new LinkedList<Object>();
      //Available to ‘chat’
      result.add(org.xmpp.packet.Presence.Show.chat);
      result.add(“Available for customer enquiry”);
      result.add(5); //Priority
      return (result);
   }

Before I conclude this blog, I would like to add that any subscription to the component is not handle by the XMPP server viz. fred@batcomputer subscription to query@customer.batcomputer should be handle by the component (CustomerService). In the example above you should probably save the senders JID if you want to do something with it later eg. notifying them that the service is going away when you are shutting the service down. Here is the modifed presenceHandler() with the sender’s JID

   //Method to handle subscription
   @PresenceType(type=org.xmpp.packet.Presence.Type.subscribe)
    public Object handleSubscription(@From JID from) {
      //Persist sender
         …
      return (org.xmpp.packet.Presence.Type.subscribed);
   }

Vorpal supports component lifecycle event which allows you to send presence info to your subscribers. I’ll blog about lifecycle and other miscellaneous features in an upcoming blog. For the impatient, see this as an example of using lifecycle events.

The latest build of the project is available here.

Till next time

XMPP Forms

Up till now, all my examples pertaining to exchanging data between the client and the external component have been using <message>. However there is a more structured way of exchanging data using forms (XEP-0004) very much like HTTP forms. The XMPP forms has a very rich structure; the following points provide a quick overview of XMPP data forms
  • firstly all the fields in the form are typed (or not, if you so choose); types includes ‘primitives’  like String, JID, boolean. Field can have attributes like hidden, fixed (label) and password. Furthermore fields can also be multivalued viz. a collection. The following shows an example of a XMPP form

<x xmlns=’jabber:x:data’ type=’form’>
   <title>Bot Configuration</title>
   <instructions>Fill out this form to configure your new bot!</instructions>
   <field type=’hidden’ var=’FORM_TYPE’>
      <value>jabber:bot</value>
   </field>
   <field type=’list-multi’
         label=’What features will the bot support?’ var=’features’>
      <option label=’Contests’><value>contests</value></option>
      <option label=’News’><value>news</value></option>
      <option label=’Polls’><value>polls</value></option>
      <option label=’Reminders’><value>reminders</value></option>
      <option label=’Search’><value>search</value></option>
      <value>news</value>
      <value>search</value>
         …
</x>

  • each form is denoted by a “type” which defines the semantics of the form. The type can be form, submit, cancel and result. In the example above, we see that the type is ‘form’; this means that the party that is submitting the form is asking the receiver to fill in the form.
  • XMPP forms can also contain multiple items; for example when you submit a Google search, Google will list multiple results in a page. All these result items contain the same structure like a text heading, a URL, a short description of the result. XMPP form can model this structure. A form of this type consist of 2 parts: a ‘header’, between a pair of <reported> tags, contains the structure of each <item> and the item itself with just the values. The following is an example of this type of form

<x xmlns=’jabber:x:data’ type=’result’>
   <title>Google Search: verona</title>
      <reported>
         <field var=’name’/>
         <field var=’url’/>
      </reported>
      <item>
         <field var=’name’>
            <value>Comune di Verona – Benvenuti nel sito ufficiale</value>
         </field>
         <field var=’url’>
            <value>http://www.comune.verona.it/</value&gt;
         </field>
      </item>
      <item>
         <field var=’name’>
            <value>benvenuto!</value>
         </field>
         <field var=’url’>
            <value>http://www.hellasverona.it/</value&gt;
         </field>
      </item>
         …
</x>

  • A XMPP form can be embedded into any of the 3 XMPP packets; the implication of this is that a XMPP form can be used in many different context for example a form can be used in an IQ packet to configure a MUC room or in a <message> packet to solicit details from a user

@DataForm Annotation

Vorpal allows you to manipulate data forms very easily through @DataForm annotation together with some powerful mapping capabilities. There are 2 use cases: the first is unmarshalling/unserializing a data form from a packet and the second is creating a data form to be returned as result.

Processing DataForm

Lets look at capturing a data form from an incoming packet. Assume we have the following incoming packet

<iq id=”F80xW-15″ to=”query@customer.batcomputer” type=”get“>
   <query xmlns=”uri:customer_query“>
      <x xmlns=”jabber:x:data” type=”form”>
         <field var=”customerId” type=”text-single”>
            <value>1</value>
         </field>
         <field var=”name” type=”text-single”/>
         <field var=”addressline1″ type=”text-single”/>
         <field var=”addressline2″ type=”text-single”/>
         <field var=”city” type=”text-single”/>
         <field var=”zip” type=”text-single”/>
         <field var=”state” type=”text-single”/>
         <field var=”phone” type=”text-single”/>
         <field var=”fax” type=”text-single”/>
         <field var=”email” type=”text-single”/>
         <field var=”discountCode” type=”text-single”/>
         <field var=”creditLimit” type=”text-single”/>
      </x>
   </query>
</iq>

In the packet example shown above, the packet contains a data form in <query>. The idea here is that we have an empty form except the customerId field. query@customer.batcomputer service will lookup the customer id (customerId field), from the database, fill in the form and return it to the submitter (data form type is form). The following code shows how we might handle this packet

@RequestScoped
@IQ
@Query(“uri:customer_query”)
public class ProcessQuery {
   @PersistenceContext EntityManager em;

   @Field(name=”customerId”, parameter=”{custId}”)
   public Object process(@Bind(“custId”) int custId) {
      Customer customer = em.find(Customer.class, custId);
      //etc. etc
   }

Lets go through the code

  1. we have a @Query (see disco blog) annotation which handles only uri:customer_query namespaced query.
  2. Next we have a @Field annotation which only fires process() method if the data form has a field call customerId. By using a @Field annotation we are assuming that the packet has a data form. Vorpal will look for a XMPP data form in the ‘usual’ places; in <iq> that ‘usual’ place translate to inside the child of <iq> packet which in this example will be in <query>. For <message> and <presence>, Vorpal will look for a data form as a direct child of <message> and <presence> packets. Any other location you’ll have to use XmlPath annotation, which is an annotation for XPath, from com.kenai.jabberwocky.framework package

Instead of using @Field to fire process(), you can also use @DataForm annotation:

   @DataForm
   public Object process() {

process() will fire if there is a data form in the packet in the ‘usual’ place. Of course that example complete ignores how we get the customer’s id which will be the subject of our next section.

Unmarshalling DataForm

There are 3 ways that you can get a data form into your message handler; the first and simplest way is to simply inject it into a DataForm object. The following is an example of how you do this

@RequestScoped
@IQ @Query(“uri:customer_query”)
public class ProcessQuery {
   @PersistenceContext EntityManager em;  
   @DataForm org.xmpp.forms.DataForm customerForm;

A second method is to inject the form into a Map (map injection). As you might have guessed, the keys of the Map are the form’s name, and the value(s) are converted into their default Java type based on the field type. The following table shows this conversion.

DataForm type Default Java type
boolean java.lang.Boolean
fixed fixed fields are ignored. Will also not appear in map injection and form binding (see below)
hidden See text-single below
jid-single org.xmpp.packet.JID
text-single java.lang.Boolean if it is ‘true’/’false’, java.util.Date if we can parse it, java.lang.Long or java.lang.Double if it is a ‘numeric’ string, java.lang.String otherwise
text-private char[] viz. an array of character. Inspired from JPasswordField
jid-multi java.util.Collection<JID>
list-multi java.util.Collection<Object> where Object will follow the conversion rule of text-single
text-multi java.util.List<String>
list-single As text-single

If the field type is missing, Vorpal will try to guess. So you can inject a data form into a Map like so

@DataForm Map<String, Object> customerForm;

or

//Using the non generic Map which is exactly the same as above
@DataForm Map customerForm;

You can also use Map<String, String>; in this case all the values will all be String. For ‘multi’ field types like text-multi, list-multi, jid-multi, the value will be a comma separated list of the field values. Besides injecting the form values into a Map, you can also get the form field’s type by specifying FormField.Type as the second parameterized type in Map. The following example shows how forms injection works

//Map the value
@DataForm Map<String, Object> customerForm;
//Map the field type
@DataForm Map<String, FormField.Type> fieldType;

for (String fieldName: fieldType.keySet()
   System.out.println(“Field name: %1$s, value: %2$s, type: %3$s”
         , fieldName, customerForm.get(fieldName), fieldType.get(fieldName));

A third way to read the value from a data form is to use forms binding. Forms binding is very similar to JAXB in that you map a data form into a Java object. The following Java object creates a binding to our customer query form example shown above

@DataForm
public class Customer {
   …
   public int getCustomerId() { …
   public void setCustomerId(int id) { …

   @FormField(name=”addressLine1″)
   public String getAddress1() { …
   public void setAddress1(String addr1) { …

   …
}

  • Firstly annotate your Java object with @DataForm to tell Vorpal that you want to use this class to bind (marshall/unmarshall) to a form. Vorpal will then try to match your JavaBean property names with the field name and copy the values from the form to the instance or vice versa. Type conversion is based on the type of the form
  • If for some reason, you need to override the above behaviour, annotate the JavaBean accessor with @FormField providing the field name that we should bind to and optionally the type
  • At the moment forms binding does not have an equivalent @XmlTransient to ignore a property

Now to bind Customer to a data form, do the following

@DataForm Customer customerForm;

Marshalling DataForm

After you have process the customer query, you’ll now need to return the form to the sender. Again the simplest way to do this is to create a DataForm object. If you do not wish to manipulate DataForm directly, Vorpal has a utility class call DataFormBuilder. Assume you would like to create the following data form

<x xmlns=”jabber:x:data” type=”form”>
   <field var=”customerId” type=”text-single”>
      <value>1</value>
   </field>
   <field var=”name” type=”text-single”>
      <value>JumboCom</value>
   </field>
   <field var=”address” type=”text-multi”>
      <value>111 E. Las Olas Blvd</value>
      <value>Fort Lauderdale</value>
      <value>33015 FL</value>
   </field>
   …
</x>

you perform do the following

DataFormBuilder builder = DataFormBuilder.create(DataForm.Type.result);
builder.field(“customerId”).textField(“1”)
      //The following is a longer version of .textField()
      .field(“name”).type(FormField.Type.text_single).value(“JumboCom”)
      .field(“address”).textField(“111 E. Las Olas Blvd”, “Fort Lauderdale”, “33015 FL”);
DataForm result = builder.build();

DataFormBuilder uses the fluent style API so using it is quite straightforward. If your form contains multiple result, DataFormBuilder handles that as well

DataFormBuilder builder = DataFormBuilder.create(DataForm.Type.result);
//Build the ‘header
builder.startReported()
      .field(“customerId”).type(FormField.Type.text_single)
      .field(“name”).type(FormField.Type.text_single)
      .field(“address”).type(FormField.Type.text_multi)
      //Other headers…
.endReported();

//For each row
builder.startItem()
      .field(“customerId”).value(“1”)
      .field(“name”).value(“JumboCom”)
      .field(“address”).values(“111 E. Las Olas Blvd”, “Fort Lauderdale”, “33015 FL”)
      …
.endItem();

//Next row
builder.startItem()
      .field(“customerId”).value(

You can also return a Map as your result. This is the reverse of the marshalling process that I’ve described above. If you return multiple result, then return a list (or any Collection) of Maps like so List<Map<String, Object>> or just List<Map>.

Finally results can also be returned using forms binding. Again if you returning multiple result using forms binding, then return a list of your objects eg. List<Customer>

Lets complete our ProcessQuery handler above using forms binding to return the result

@RequestScoped
@IQ @Query(“uri:customer_query”)
public class ProcessQuery {
   @PersistenceContext EntityManager
   @Field(name=”customerId”, parameter=”{custId}”)
   public Object process(@Bind(“custId”) int custId) {
      Customer cust = em.find(Customer.class, custId);
      if (null == cust)
         return (ErrorPacketBuilder.create(Condition.item_not_found));
      //Vorpal will default form to result if type is not specified
      return (cust);
   }
}

Since Customer supports both JPA and forms binding we must make sure that it has the appropriate annotations

@Entity // for JPA
@DataForm
public class Customer {
   …

Download the latest bundle here (look for “Latest XMPP Project” entry) if you intend to try out Vorpal.

Till next time

Screencast: Developing Discoverable XMPP Components with Vorpal

A screencast explaining how disco#info and disco#items works in XMPP. There is also a ‘live’ coding show how to use @IQ and @Query nnotation.

Comments and feedback are welcomed.

Another Screencast – Stateful Objects with Conversation

I’ve really caught the screencast bug; here is another screencast on conversation support in Vorpal. In the screencast I use Vorpal to develop an Eliza service.

Here is how it works. IM users establish a chat session with eliza@arkham.batcomputer JID (or whatever subdomain you choose to deploy it in). If the in coming messages to Eliza has <thread> element, then Vorpal can use that to establish a conversation.

To begin a ‘therapy session’ with Eliza, send to eliza@arkham.batcomputer a message with start as the message content. Vorpal will create an instance of Eliza and hold that for the duration of the conversation. When you decided to end the session, simply send it a message with quit. Vorpal will clear all the objects in the conversation’s context.

Note: the above screencast is about 16:28 mins. Not sure why Youtube thinks its 49:18 mins

I’ve blogged extensively about conversation support and the programming model in my previous posting call Conversations with Vorpal.

You can get the source code of the demo here.
Get the latest Jabberwocky bundle here.
The Eliza source used in the screencast is available from http://chayden.net/eliza/Eliza.html.

Till next time.

Screencast – Developing XMPP Services with Jabberwocky and Vorpal

I’ve decided to move to the 21st century by recording my first screencast. After hunting and testing various Linux tools, I’ve settled on recordMyDesktop.

The following 2 screencast on this blog are my effort.

So what’s the screencast about? I’ve blog extensively about XMPP and the two framework that I’ve been working on, Jabberwocky and Vorpal. I thought it’ll be nice to show how to use these frameworks.

Part 1 of the screencast talks about the various ways you can develop XMPP services.
These includes service bots, server plugin and external component. The
second segment of this part describes a use case for querying a
database using XMPP.

In part 2 of the screencast, I will show how to implement the use case described above with Jabberwocky and Vorpal along with JavaEE services including CDI and JPA.

The source for the code from part 2 can be found here.

Please provide your comments and feedbacks. Till next time.

Convesations with Vorpal

In my last blog, I talk about using Vorpal with CDI. As you probably know, one of the responsibilities of CDI is to manage the lifecycle of Java objects within a web application for example. All the examples shown from that blog were request scoped.

In this blog, I’ll talk about using conversation with CDI. I’ve talked abit about conversation support here. I’ll expand on those concepts with regards to CDI.

How to Hold A Conversation

Every XMPP <message> packet that has the <thread> element is capable of supporting conversation in Vorpal.  See this if you are not familiar with conversation. Let look at how to use conversation by way of the shopping cart use case. 

We have a shopping client that will send items that we wish to purchase to cart@some_XMPP_domain.org. The items are carried in a separate XML element (uri:items) in a <message> packet. On receiving such a message, our shopping cart service will see if a conversation has been initiated; if not, the service will start a conversation. It will also create a ShoppngCart object and save that in the ConversationContext

The following class shows how this is done:

@ConversationScoped
@Message
@To(“cart@{__domain__}”)
public class ShoppingCartHandler {
   @Inject @Named(“__conversation__”) Conversation conv;
   @Inject ThreadID threadId;
   @Inject ConversationContext ctx;

   @XmlElement(“uri:items”, parameter=”{item}”)
   private List<Object> shopping(@Bind(“{item}”) Items items) {
      ShoppingCart cart;
      if (conv.isTransient()) {
         //Starts the conversation
         conv.begin();
         //Create the shopping cart
         ctx.setAttribute(“shopping-cart”, new ShoppingCart());
      }
      cart = (ShoppingCart)ctx.getAttribute(“shopping-cart”);
      // Save items into cart – not shown
   }
}

So to support conversation, annotate the class with with one of these annotations

  • javax.enterprise.context.RequestScoped
  • com.kenai.jabberwocky.framework.ConversationScoped, not javax.enterprise.context.ConversationScoped
  • javax.enterprise.context.ApplicationScoped – the use of this annotation this is not recommended. Will explain later

Secondly inject one of these into the message handler

  • Conversation – this allows us to start and terminate a conversation. Furthermore, when you are injecting Conversation, you must qualify it with @Named(“__conversation__”). This is to avoid confusing the container into injecting the default JSF conversation. The usage of this class is exactly the same as JSF.
  • ThreadID – this will give you the thread id from <thread> element in your message
  • ConversationContext – this is very similar to HttpSession. It allows data pertaining to the conversation to be saved like our ShoppingCart object; also all message handles/objects in a session will have access to the same ConversationContext thereby facilitating data sharing.

When ShoppingCartHandler.shopping() fires (see this on method resolution), we first checks to see if the conversation is transient; if it is, then we start the conversation, creates a new instance of ShoppingCart object and save that in our ConversationContext. ConversationContext are persistent and is bound to that conversation once its started.

Starting a conversation cause all classes that are annotated with ConversationScoped to be persisted in that conversation context. When a conversation ends, all these cached objects will be cleared. RequestScoped objects created under a conversation are not persisted. Conversations do not need to be started in a ConversationScoped object; you can call Conversation.start() from within a RequestScoped or an ApplicationScoped message handler. In fact you can have a ‘conversation’ from all RequestScoped objects. ApplicationScoped objects are never cleared when a conversation ends.

Vorpal can also be used without CDI. In that case if you have started a conversation, then all message handlers fired during the conversation will be persisted and will only be released when the conversation ends.

Now let’s look at how we handle checkout:

@RequestScoped
@Message
@To(“cart@{__domain__}”)
public class CheckoutHandler {
   @Inject @Named(PredefinedBindings.CONVERSATION) Conversation conv;
   @Inject ConversationContext ctx;

   @Body(“checkout {*ignore}”)
   public String checkout() {
      ShoppingCart cart;
      if (conv.isTransient())
         return (“You have not done any shopping!”);
     
      cart = (ShoppingCart)ctx.getAttribute(“shopping-cart”);
      //Perform checkout
         …
      //Terminate the conversation – free all objects
      conv.end();
         …
   }

}

To perform a checkout, all you have to do is send a message with ‘checkout‘ as the first word in the message’s body; this will cause CheckoutHandler.checkout() to be fired. We first check if a conversation has been started, sending an appropriate message back to the client if not. We then get the ShoppingCart object from ConversationContext and perform the checkout. Finally we end the conversation by calling Conversation.end(). This will free ConversationContext and also all ConversationScoped object created during this conversation.

Attributes Reinjection

If you are familiar with CDI, once injection have been performed on persistent object like SessionScoped or even ApplicationScoped objects, their members are no longer reinjected. Persistent objects in Vorpal are reinjected whenever they fire. Lets look at a simple example

@ConversationScoped
@Message
@XmlElement(“uri:items”, parameter=”{items}”)
public class ModifyShoppingCart {
   @Inject @Body String body;
   @Inject @Named(PredefinedBindings.CONVERSATION) Conversation conv;
   …

}

In the above message handler, a new instance of ModifyShoppingCart cart will be created if a conversation is not started. So when we create a new instance of ModifyShoppingCart, we will inject the message’s body into body. If however a conversation have been started, then an instance of ModifyShoppingCart will be created and save in the conversation’s context; and it is this instance that will be reused for that particular conversation, if it fires again, until we terminate the conversation.

Unlike the default CDI injection semantics, whenever we reuse a message handler object from a conversation context, all injected attributes pertaining to the incoming message will be refreshed; for example, in ModifyShoppingCart, we are injecting the message body into body member. So whenever ModifyShoppingCart is fired again under the same conversation, body member will be injected with the latest value in <body> from the incoming message. This is also the reason why its a bad idea to have ApplicationScoped objects are message handles.

If you wish to try out conversation support, get the latest build from here. Let me know what you think. Till next time

%d bloggers like this: