Writing External Components (for Jabberwocky) with NetBeans

I’ve been working on a NetBeans plugin for the past few weeks. I wanted the plugin because I wanted a place where you could develop, debug and deploy Jabberwocky external components. Download the latest package here. Select the Mayday 2011 download.
The package contains the following

  1. xmpp-gf-container.jar, jabberwocky_support.jar – the latest and greatest Jabberwocky container. I’ve hope to avoid updating the containers but certain issues (see below) have forced me to make changes to the container. See here on how to install the containers if you are new to Jabberwocky.
  2. update directory – this directory contains NetBeans plugin and also the Vorpal framework binaries which I talked about in my previous blog entry

Before I begin I have to say that I have made some rather major modifications to Jabberwocky packaging. Previously, it Jabberwocky components are XAR packages which is basically a JAR file. It is now a WAR package, yes it’s a JavaEE 6 compliant Web ARchive. There are 2 main reason for this change, the first is to do with Glassfish’s architecture (which sort of prevents me from doing certain things); the second is that make this change will allow me to work better with other Glassfish container. Also having a standard WAR package it really makes writing the NetBeans plugin a lot easier.

Installing NetBeans Plugin

The plugin is written for the latest version of NetBeans 7.0. (Don’t even bother trying it on any version other than 7.0). Startup NetBeans 7.0, go to Tools | Plugins | Downloaded | Add Plugins… Navigate to the update directory and select all the NBMs files as shown in the diagram below.


If this or any subsequent images is not clear, right click on the image and select View Image

Creating Jabberwocky External Component

Create a Web application in NetBeans. Select File | New Project | Java Web | Web Application. See diagram below

Select Next for the next 2 screens entering the relevant details for your web application like project name, context path, etc. Then you will come to the fourth screen which is the Frameworks screen as shown below

Select Jabberwocky framework. What this will now do is add the relevant libraries and deployment files into the WAR package. First choose the type of component

  1. Jabberwocky framework – this the the Vorpal framework. If you select this you do not have to fill in the package and class name. The framework will handle that for you
  2. AbstractComponent – selecting this means that you intend to create your external component by extending com.xmpp.component.AbstractComponent abstract class. Enter the package and class name that will extend AbstractComponent.
  3. Component – selecting this means that you intend to implement org.xmpp.component.Component interface. Enter the package and class name that will implement Component.

If your component has any properties, click on the Properties tab and enter the properties as name/value pair. Click Finish to complete the setup.

NetBeans will now display the project and open the xep-0114.xml configuration file.

If xep-0114 file is not opened in the editor area, double click on xep-0114 file in the project window to your left. The editor allows us to configure our external component when we deploy to Jabberwocky. Right at the top is the main component class. If you are using Vorpal (Jabberwocky framework), then you should not change the default class (com.kenai.jabberwocky.core.JabberwockyComponent). Otherwise if you are using the other two types of components, then the fully qualified class name will be display here and you can change this. But remember you can only deploy one external component per WAR package.

Next comes the subdomain properties. This is the subdomain that your component is going to deploy to. Enter the subdomain name, domain and the port number. The Shared secret field is disable. What this means is that you have defined the subdomain in Jabberwocky using the asadmin create-xmpp-subdomain; see this blog.

However if you want to automatically create the subdomain as you deploy the external component, select Create subdomain checkbox. This will enable the Shared secret field. Enter the shared secret of your subdomain (eg. landofthegiants from above is uppercase) or leave it blank to use the default shared secret. Note that this option only creates the subdomain definition in Jabberwock and not with the XMPP server. The Cleanup checkbox ask Jabberwocky to cleanup the subdomain definition when you undeploy your component.

Now you can write your component. If you are using Vorpal, then you need to write some message handlers. My previous blog gives a brief tutorial on using Vorpal.

If you are using AbstractComponent or Component, then the plugin will generate an appropriate template for you.

You need to also ensure that the Glassfish instance that you are deploying to supports Jabberwocky. To check if the Glassfish instance supports Jabberwocky, right click on the project node (eg. EchoUpperCaseComponent in the diagram above) and select Properties. The following dialog box will open.

The Server combo box will show a list of Glassfish instances that supports Jabberwocky. If the Glassfish instance that you have chose as your deployment server supports Jabberwocky, then that instance will be displayed here. If however you have accidentally selected Tomcat, then this combo box will be blank. Pull down the combo box to see which instance supports Jabberwocky. Also changing this do not change the actual deployment server of the web project. (I’ll fix this one day). You have to select Run under Categories and chose a Glassfish instance that matches this combo box.

Finally you are ready to deploy. Right click on the project node and select Deploy.

If all goes well you will see some communication between your component and the XMPP server in the output window.

If you switch over to the Services tab, you should also see your component deployed under Applications.

Note: if you fail to see any communications between your component and the XMPP server and you are sure its not because of your component, then undeploy your component from Glassfish. Open the build.xml file and save it. Then build and redeploy your component.

With this plugin I hope to make external component development on Jabberwocky easier. In my next blog I’ll show you how you can add external component to an existing WAR file.

Till then, give me feedbacks (love it, indifferent, sucks). If you discover any bugs send me a comment or file a bug at the Jabberwocky home.

Vorpal – A XMPP Application Framework

I have been using JAX-RS API (tutorial here) a lot over the past year and I really like the the API. Its simple yet flexible enough for advance usage. Clever use of annotations, flexible method signatures and works with any Servlet container. So I thought why not create a XMPP application framework for Jabberwocky. This framework, which I’ll call Vorpal, will be modelled after JAX-RS API. I’ve intentionally kept the current scope small by supporting only <message> viz. the Vorpal framework will only know how to process <message>.

Why <message>? Well, the main reason is that <message> (chat, groupchat, etc) is probably the most commonly used. It’s quite flexible in its usage and it supports both stateless and stateful use cases. As I’m experimenting with Vorpal I feel <message> offers the best model to work with.

The best way to learn something is to study some examples; so here are 4 examples showing some of the features (not exhaustive) that Vorpal currently supports.

Vorpal Tutorial

Assume we have the following incoming message

<message type=’chat’ id=’abc’ to=’romeo@montague.verona’ from=’juliet@capulet’>
   <active xmlns=’http://jabber.org/protocol/chatstates’/&gt;
   <body>You kiss by the book</hello>
</message>

Example 1

To capture this chat message write the following class

@Message
public class ProcessMessage {
   @Body(“{body}”)
   public String fromJuliet(@Parameter(“body”) String message) {
      return (message.toUpperCase());
   }
}

The @Message is a class level annotation that tells Vorpal that this class is going to handle <message>. Next write a method that is going to process the message and annotate it with @Body. @Body tells the framework that this is the method to process the message’s body viz. <body>. The parameter {body} specifies a ‘capture’ and is used to capture the content of the message’s payload and this is mapped by the @Parameter in fromJuliet() method to the formal parameter message. When you specify the capture parameter’s name in @Parameter, do not enclose the name with {}.

When we return a String after processing the message, the framework will now create the following reply back to juilet@capulet inserting the String in the body.

<message type=’chat’ id=’xyz’ from=’romeo@montague.verona’ to=’julie@capulet’>
   <body>YOU KISS BY THE BOOK</hello>
</message>

All message handler methods must be annotated, either with @Body or others, in order for them to be selected for invocation.

Example 2

Let say we only want to reserve fromJuliet() exclusively for messages from juliet@capulet; all other messages will be handle by a different method handleOthers(). We could express this in the following way

@Message @Body(“{body}”)
public class ProcessMessage {
   @From(“juliet@capulet”)
   public String fromJuliet(@Parameter(“body”) String message) {
      return (message.toUpperCase());
   }
   @From(“{anyone}@{anydomain}”)
   public String handleOthers(@Parameter(“anyone”) String name
         ,
@Parameter(“body”) String message) {
      return (“Hello ” + name + “,\n” + message);
   }
}

Firstly notice that we have move @Body to the class level; this is so that {body} is available to both fromJuliet() and handleOthers() methods. Secondly note the capture parameters in both the @From annotations. In the first annotation with juliet@capulet string; the string do not contain a pair of {}. This signifies that it is a literal and not a capture. So for fromJuliet() method to ‘fire’, the from attribute in <message> must match this literal value.

As for the second @From annotation, this is a template with a mix of capture and literal. In this case we are breaking up an incoming message’s from JID and map that to two capture parameters. Assume we have the following two JIDs mercutio@verona and holmer@springfield/moestavern sending in messages then the following diagram shows how these JIDs are captured.

{anyone} will capture mercutio and holmer and {anydomain} will capture vernoa and springfield/moestavern respective. The capture mechanism is basically a simple pattern matcher; since the @ is a literal, the incoming JID will be broken into two parts and assigned to the two respective capture parameters. If we wish to break out the resource from JID, then one could use the following template {anyone}@{anydomain}/{anyresource}.

Alert readers will notice that the JID juliet@capulet could well have matched @From(“juliet@capulet”) and @From(“{anyone}@{anydomain}”). Lets leave this discussion till after example 3.

Example 3

In the following example we want be be notified when when someone leaves so that we can send them a goodbye message; to do this, we have to examine chatstate. Setup the following class

@Message @Body(“{body}”) @From(“{anyone}@{anydomain}”)
public class ProcessMessage {
   @From(“juliet@capulet”)
   public String fromJuliet(@Parameter(“body”) String message) {
      return (message.toUpperCase());
   }
  
@From(“juliet@capulet”)
   @Namespace(uri=”http://http://jabber.org/protocol/chatstates&#8221;, tag=”gone”)
   public String goodbyeJuliet(@Parameter(“anyone”) String name) {
      return (“Parting is such sweet sorrow”);
   }
  
   @Namespace(uri=”http://http://jabber.org/protocol/chatstates&#8221;, parameter=”{chatstate}”)
   public String handleOthers(@Parameter(“anyone”) String name
         ,
@Parameter(“body”) String message)
         , @Parameter(“chatstate”) Element chatstate) {
      //Using JDK7 strings in switch
      switch (chatstate.getName()) {
         case “active”:
            return (“Hello ” + name + “,\n” + message);
         case “gone”:
            return (“Goodbye ” + name + “, see you next time”);
         case “inactive”:
            return (“Why so quiet ” + name);
         default:
      }
      return (null);
   }

}

Using @Namespace, we have access all packet extension within a packet. You may use @Namespace to specify either just the tag of the extension, or the namespace or both. In the first use of @Namespace, we specify that if juliet@capulet leaves, then we send her a sappy parting message. In the second example handleOthers(), we only specify the namespace of chatstates. There is an additional parameter field which specifies the name of the capture parameter. Now we map this to an Element type. In the body of handleOthers(), we examine the tag and give appropriate responses to active, gone and inactive. Anything else we return a null which tells Vorpal not to send any response message back. If your method is not going to return anything ever, declare the return type as void.

@Namespace may be mapped to either Element (dom4j) or a JAXB object. It can also be mapped to a String. Using dom4j/JAXB you get access into the packet extension’s document.

Soapbox – Method Resolution

So how does method resolution takes place? In example 2, you will notice that JID juliet@capulet could have matched both @From(“juliet@capulet”) and @From(“{anyone}@{anydomain}”) and therefore could have triggered both fromJuliet() and handleOthers() respectively. Before any resolution takes place, classes and methods are sorted. All classes/methods are sorted in descending order of the number of annotations. If there are 2 or more methods with the same number of annotations, then they are lexically ordered based on their method names. Based on this ordering method, the methods in ProcessMessage class in example 3 above, are ordered in the following manner

  1. goodbyeJuilet() – 2 annotations
  2. fromJuliet() – 1 annotation, lexically smaller that handleOthers()
  3. handleOthers() – 1 annotation

When a message from juliet@capulet arrives, goodbyeJuliet() will be examined first; if the message contains a chatstates extension and that tag is gone, then goodbyeJuliet() will be selected for invocation. However if the packet’s chatstate’s tag is not gone or the packet does not contain a chatstates extension, then the second method will be selected for evaluation. Since fromJuliet() only contains the @From annotation and there is a match, fromJuliet() is invoked.

Simply stated, method resolution goes from more specific (being more annotation) to general (at least 1 annotation)

Example 4

In our final example, if we receive a message to info@montague.verona, then we would like to reply with a “thank you for enquiring” message along with a vCard as part of the message extension. The reply we wish to construct looks the like following message

<message type=’chat’ id=’abc’ to=’inquisitive@verona’ from=’info@montague.verona‘>
   <body>Dear inqusitive, thank you for enquiring. Please find attached vCard</hello>
   <vCard xmlns=’vcard-temp’>
      <fn>Romeo Montague</fn>
      <nickname>Romeo</nickname>
         …
   </vCard>
</message>

where the green is our text reply and the purple is the vCard. The vCard extension can be constructed using Element or JAXB. Both of these are supported directly in Vorpal. For simplicity, I’ll use JAXB class to hold the vCard data

@XmlRootElement(name=”vCard”, namespace=”vcard-temp”)
@XmlAccessorType(XmlAccessType.PROPERTY)
public class VCard {
   private String formattedName;
   private String nickname;
   …
   @XmlElement(name=”fn”)
   public String getFormattedName() {
      return (formattedName);
   }
   …

The following method sendInfo() shows how to construct the reply message

   @Order(1)
   @To(“info@montague.verona”)
   public Set<Object> sendInfo(@Parameter(“anyone”) String name) {
      Set<Object> reply = new HashSet<Object>();
      //Add a string for the message’s body
      reply.add(“Dear ” + name + “, thank you for enquiring. Please find attached vCard”);
      //Create vCard object and populate it
      VCard vCard = new VCard();
      vCard.setFormattedName(“Romeo Montague”);
      …
      //Add this to the reply set
      reply.add(vCard);
      return (reply);
   }

Wherever you have more than one value to be packaged into the reply packet, return a Collection type (Set, List, Queue, etc.). You can now populate the collection with either dom4j Element, JAXB object or String. Elements and JAXB objects will be added as part of the packet’s extension so ensure that you have proper namespaces for these XML objects. Strings and other non Element or JAXB objects will be set as the message’s body content. If an object is not a String, then the toString() method will be invoked to obtain a String.

Note also the @Order annotation. This annotation overrides the method ordering scheme which I’ve talked about earlier. @Order are sorted in ascending order; furthermore, any method that has @Order annotation will be ‘smaller’ than any other method that do not have this annotation. So, @Order methods will be resolved first followed by non @Order methods. If 2 or more methods have the same order number, then the previously discuss sorting method will be applied. Together with sendInfo(), the method resolution order is now as follows

  1. sendInfo() – ordered 1
  2. goodbyeJuilet() – 2 annotations
  3. fromJuliet() – 1 annotation, lexically smaller that handleOthers()
  4. handleOthers() – 1 annotation

In this particular case, if we do not annotate this with @Order, then messages for info@montague.verona might be gobbled up by handleOthers() because although both sendInfo() and handleOthers() has the same number of annotation, the latter is lexically lower than the former so it will be evaluated first.

I’ll be releasing Vorpal framework soon. Meanwhile please let me know what you think of Vorapl. Till next time.

%d bloggers like this: