Photostream App – Part 2

In the the second part of the “Photostream” trilogy, we will look at how the server notifies all the clients who are observing its stream. There are 2 ways we can do this; either by using server sent events or with websocket.

Since JavaEE 7 supports websocket I’ll be using websocket. Websocket is a 2 way communication channel. In photostream app, the notification/data only flows on way viz. from the server to the client (those observing our photostream) so server sent event (SSE) is actually more appropriate. But to use SSE in JavaEE (in Glassfish/Payara in particular), you have to use add additional libraries.

In you’re using Glassfish/Payara and you would like to try SSE, see this document.

The source code for part 2 is available here.

Till next time.

Vorpal2 Client

Since rewriting Vorpal2 core framework, I’ve made a number of changes to the client side. I first introduce Vorpal client here; in Vorpal2 client, the programming model remains the same but bootstrapping and login in XMPP server have been change. Lets look at these changes.

Component Class

Every Vorpal application, whether its server or client side, requires a configuration file for startup. This is an XML file. The only change here is the component-class entry. This has changed from com.kenai.jabberwocky.framework.client.JabberwockyClientComponent to c.k.j.f.c.XMPPClientComponent. If you have written a client application, the following in red is what you need to change in your configuration file

<connection port=”5222″ domain=”batcomputer”>
   <component-class name=”com.kenai.jabberwocky.framework.client.XMPPClientComponent”/>
   <classes-root>classes</classes-root>
   <packages>
      <package name=”com.acme.xmpp.client”/>
   </packages>
   <properties>
      <property name=”vorpal.component.description” value=”A component to query the customer’s database”/>
      <property name=”vorpal.component.name” value=”Customer Query Client”/>
   </properties>
</connection>

Bootstrapping Vorpal2 Client

A typical Vorapl2 client starts in 2 different phases; the first is to start CDI (using Weld). You can read about starting CDI in Java SE here. The second phase is to start Vorpal2 framework which will in turn start your Vorpal2 Client application. This is typically done by capturing the ContainerInitialized event.

The following code snippet shows how this is done.

@Inject ClientConnectionManager mgr;

private void containerInitialized(@Observes ContainerInitialized ciEvt) {
   String username = …
   String password = …
   ClientConnectionManager.Connection conn = mgr.createConnection();
   conn.load(new File(“client.xml”));
   if (!conn.login(username, password)) {
         //Authentication failed
   }

   //Vorpal2 client is now started
}

private void containerShutdown(@Observes BeforeShutdown bsEvt) {
   mgr.getConnection().logout();
}

Once we got the ContainerInitialized event, you can create a connection from ClientConnectionManager. The ClientConnectinManager is an ApplicationScoped object which is injected into your startup class. The next step is to load the configuration file. The load() method accepts the configuration either as an InputStream, a File or a ClientComponentConfiguration object. The ClientComponentConfiguration is the object representation of the configuration file; it is JAXB enabled so you can use JAXB to unmarshall a XML configuration file. Alternatively you can also use the helper method ClientComponentConfiguration.read() to return an instance of ClientComponentConfiguration. read() takes either a File or an InputStream as parameter.

After successfully loading the configuration, you can now attempt to login. The login() method will return a false if it fails to login. You can optionally pass a resource into the login() method.

To close a connection, retrieve the default connection from ClientConnectionManager.getConnection() and call the logout() method.

Running Vorpal2 Client

Vorpal2 client applications are dependent on the following 4 runtime JAR files

  • vorpal2.jar
  • weld-se-core.jar
  • weld-se.jar
  • jabberwocky_support2.jar

Due to classloading issues with log4j, jabberwocky_support2.jar MUST the the last JAR file in your CLASSPATH; otherwise Weld will fail initialization.

Client support currently is still very basic. Only clear connections are supported; SSL and other features are planned.

To try Vorpal2 client support, download the latest bundle from here.

New Beginnings Again!

exploring-calvin-and-hobbes

 

They say third time is a or should be charm! In this blog, I’ll talk about Vorpal2, a reworked version of Vorpal.

 

Excuses, excuses, excuses

The original Vorpal grew out of an experiment and the framework was implemented on top of AbstractComponent class from Tinder. It was a really easy way for someone like me with very little knowledge of XMPP to learn about XMPP and get the framework up and running. However due to the way AbstractComponent class works, I had to repeat a same piece of code in different places. There is no single choke point for the XMPP packets coming in and leaving the framework (for that I had to modify AbstractComponent which was not very appealing); this make implementing certain features extremely difficult and in some cases impossible.

The second issue was that I made the framework dependent on a custom Glassfish container call Jabberwocky. Whilst Jabberwocky is great in that it provided a very robust base to run the framework, integrated extremely well with Glassfish asadmin command and provided all sort of statistics on a Vorpal application, the down side was that it effectively ties Vorpal to Glassfish. Also Jabberwocky is build with Maven. So whenever there is a new release of Glassfish I have to figure out which dependencies have change, etc.

Finally testing the framework engine’s becomes difficult because of the 2 dependencies above.

So I’ve decided to reimplement Vorpal; the good news for me is that most of the framework is fine. I just have to rewrite how the Vorpal is loaded. I’ve removed Vorpal’s dependence on AbstractComponent and Jabberwocky; the startup is now done in ServletContainerInitializer. Its lightweight and in theory should run on any JavaEE 6 Web Profile compliant container. Glassfish will still be the best supported platform simply because this is where I develop and test Vorpal.

For the rest of this blog, I’ll talk about migrating from Vorpal to Vorpal2, packet filters which is a new feature available only in Vorpal2.

 

The Great Migration

No code change (except for ComponentManager)

I’m happy to say that there are no code changes going from Vorpal to Vorpal2 but if your application uses ComponentManager then you’ll have to rewrite that portion of it.  ComponentManager is an artefact of AbstractComponent. In the past I’ve allowed you to inject ComponentManager into your message handlers. This is no longer true; all the functions in ComponentManager can now be found in ComponentContext.

New JARs

The new Vorpal2 bundle can be found here (vorpal2). As before, the framework is split into 2 JARs

  • vorpal2.jar – the framework
  • jabberwocky_support2.jar – framework supporting files

If you have been using Vorpal, you’ll need to uninstall them. Delete jabberwocky.jar and jabberwocky_support.jar from $GLASSFISH_HOME/glassfish/modules directory.

As before, vorpal2.jar must be bundled with your application in WEB-INF/lib.

There are 2 ways you can install jabberwocky_support2.jar. You can either bundle that with your application in WEB-INF/lib or install it at your application’s CLASSPATH. For Glassfish this will be the $GLASSFISH_HOME/glassfish/modules directory.

At the writing of this blog, I’ve not fully migrated the NetBeans plugin to support Vorpal2 (hence the missing update directory from the download bundle). Hopefully I’ll have the plugins done by the next release. In the mean time, you’ll have to manage the build and package yourself. In NetBeans, add the the JARs from the bundle to your project’s library and remove the previous version of the libraries. Also remember that these JARs, or at the minimum vorpal2.jar, must be in WEB-INF/lib of the final WAR file.

Deployment descriptor

Vorpal uses a deployment file to connect to an XMPP server. The file is called xep-0114.xml. This file is found in WEB-INF directory. If you’re developing Vorpal applications with the NetBeans plugin, the template of this deployment file is in your project directory and its called xep-0114.txmlt.

The deployment file contains the following pieces of information

  • The XMPP domain, port number to connect to
  • The subdomain name we wish to use
  • The class name of the component to start – this is very specific to the frame
  • An option to specify the shared secret when connecting to the XMPP domain
  • An optional list of properties to be passed to the application

The file looks like the following

<subdomain domain=”batcomputer” port=”5275” name=”customer”>
   <component-class name=”com.kenai.jabberwock.framework.core.JabberwockyComponent”/>
   <create-subdomain shared-secret=”AlwaysRight” create=”true” cleanup=”true”/>
   <properties>
      <property name=”vorpal.component.name” value=”Customer service”/>
      <property name=”vorpal.component.description” value=”Customer service”/>
   </properties>
</subdomain>

What you need to do is the following

  • Change the component-class name from com.kenai.jabberwock.framework.core.Jabberwocky to com.kenai.jabberwocky.framework.core.XMPPComponentServer
  • Always specify the shared secret with create-domain. The create and cleanup attributes must be present but their values are ignored.

So the new deployment file xep-0114.xml looks like below

<subdomain domain=”batcomputer” port=”5275” name=”customer”>
   <component-class  name=”com.kenai.jabberwock.framework.core.XMPPComponentServer”/>
   <create-subdomain shared-secret=”AlwaysRight” create=”true” cleanup=”true”/>
   <properties>
      <property name=”vorpal.component.name” value=”Customer service”/>
      <property name=”vorpal.component.description” value=”Customer service”/>
   </properties>
</subdomain>

Recompile your application after you’ve made these changes.

New Features

Packet filtering

Packet filtering is one of the feature that I wanted to implement into Vorpal. But I could not do this easily under the old code base until now.

Packet filter are filters that are applied to incoming and outgoing XMPP packets. To implement a packet filter, first annotate your class with @PacketFilter and either implement RequestFilter or ResponseFilter (or both!). The following is an example of a request filter that filters out packets that are not send from the local domain

@PacketFilter
public class LocalEntityOnlyFilter implements RequestFilter {
    @Inject @Named(PredefinedBindings.DOMAIN) String domain;
    //Inspired by AbstractComponent.sentByLocalEntity(Packet packet)
    @Override
    public Packet incoming(final Packet in
          , ComponentContext context)
{
        final JID jid = in.getFrom();
        if (null != jid)
            return (in);
        String pktDomain = jid.getDomain();
        if (pktDomain.equals(domain)
               || pktDomain.endsWith("." + domain))
            return (in);
        return (null);
    }
}

Firstly we see that our filter is annotated with @PacketFilter and implements RequestFilter. So what this mean is that this filter will only monitor incoming packets viz. packets sent to the Vorpal application.

Filters are managed by CDI. so you can injected values into it. In this case we are injecting the domain name that the subcomponent is connected to. Filters are statesless so you should not use any CDI scopes on it.

In the filter, you can do anything to the packet; you can add stanzas, remove stanzas and change certain values in the packet. When you return a packet, this can be the original packet from the parameter or a totally new packet, Vorpal will take the packet and proceed with finding an appropriate handler. If you return a null, then Vorpal will discard the packet.

A ResponseFilter behaves the same way as a RequestFilter. When you implement ResponseFilter, you have to override the outgoing(Packet, ComponentContext) method which returns a Packet as well. If you return a null, then Vorpal will not send the packet.

If you have more that one request or response filter, Vorpal does not impose any ordering on them. Also if one of the filter rejects a packet, then that packet will not be processed by other filters. For example if you have 3 request filters; the first of these 3 filters rejects the packet, then that packet will not be passed to the other 2 to be processed.

Ordering sent packets

One side effect of this new version is you can now impose some order on how the packets are send out by returning a List in your message handler. The following code snippet illustrates this

@Body(“{body}”)
private List<ResponseContext> handle(@Named(“body”) String body) {
   …
}

handle() returns a List; so Vorpal will send out the packet according to the order of the packets in the list.

Let me know what you think of Vorpal2. If you have any issues, please post them to the forum. The new bundle can be found here.

Using Server Sent Events with Vorpal

bridge

I came across the following 2 blogs (here and here) on a CDI framework for server sent event (SSE) several months ago. I downloaded the source then tried it with Vorpal running on Glassfish 3.1.x. The result was a really long exception stack.

4 months later.

After publishing part 4 of on conversations, I decided to see if I have any luck with the SSE framework. I wasn’t really expecting it to work. Well it did. What is even more surprising is that it worked with Vorpal. 

What I’m going to do in this blog is explain how the SSE framework works and more importantly how you can use it with Vorpal. Its really easy.

Setup the push event stream

Firstly create a notification handler. The notification handler will maintain the connection between the browser and the web application. The following is a simple notification handler

@ServerSentEvents(“/notifications”)

public class NotificationHandler extends ServerSentEventHandler {

   public void sendMessage(String msg) {

      try {

         connection.sendMessage(msg);

      } catch (IOException ex) {

      }

   }

A few points to note: the notification handler must extend ServerSentEventHandler; this class is from the framework. You also have to annotate the class with @ServerSentEvents and specify the URL of the event stream. In this case it is notifications. More on this later.

Now you need to write a HTML/JSP/JSF/whatever page to invoke this event stream. Here is a snippet of the HTML page along with a snippet of Javascript that loads loads the event stream

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>XMPP with SSE</title>
        <script src="resources/app.js"></script>
    </h:head>
    <h:body>
        <h1>Using Vorpal with SSE</h1>       
    </h:body>
</html>

The Javascript that creates the event stream is in app.js. Here is the code

var url = ‘http://’ + document.location.host

      + “/xmppsse/notifications”;

eventSource = new EventSource(url);

eventSource.onmessage = {

   document.body.innerHTML += msg + ’<br>’;

};

The important thing here is to get the event stream URL right. If our example, this is made up of the application context of our web application (in blue) and the value that you’ve specified in @ServerSentEvent annotation (in green).

 

Pushing data to the browser

We now hook the event handler to a Vorpal application. I did a screencast on developing a customer query service which allows you to use a Jabber client to query a database, which you can find here and the source here.

Lets extend this so that whenever someone performs a query, the result is also pushed to the browser using SSE.

@Message

public class MessageHandler {

   @EJB CustomerManager mgr;

   @Inject @ServerSentEventContext(“/notifications”)

        ServerSentEventHandlerContext<NotificationHandler> ctx;

   @Body(“{id}”)

   private String handle(@Named(“id”) int id) {

      //Assume we find every record and no NPE

      String record = mgr.find(id).toString();

      //Loop through all handlers

      for (NotificationHandler nh: ctx.getHandlers())

         try {

            nh.sendMessage(record);

         } catch (Exception ex) {

            nh.close();

         }

      return (record);

   }

After we got the record from CustomerManager, which uses JPA, we loop through all the registered handlers for an event stream channel and pushes the record to them. You have to get the correct handler to push to.

In our example, we are pushing to all browser registered on notifications. So we inject an instance of ServerSentEventHandlerContext with qualifying it with @ServerSentEventContext(“notifications”).

Example code

You can download the example source from here. I’ve bundled the SSE library into the download which is a NetBeans project.

Use the following steps to setup, deploy and run the example

  1. Configure an external component on your Jabber server. The example uses customer for subdomain and AlwaysRight for shared secret (Caps!). You can always change these settings. I use Openfire for the Jabber server
  2. Make sure that you’ve installed your Glassfish with Jabberwocky container.
  3. Deploy the project to Glassfish either from NetBeans or using asadmin command. It’s probably easier if you deploy if from NetBeans
  4. Open your browser and point to http://yourserver:port/xmppsse. I’ve tested with Firefox and Chrome, latest versions.
  5. Open your Jabber client, open a chat with query@customer.your_jabber_server. Send 1
  6. You should now see your reply display in your Jabber client and in your browser.

The source code for the SSE can be found here if you wish to look at it.

Part of the code (the app.js) is taken from Bhakti Mehta’s blog. Big thanks.

Till next time.

Art of Conversation: Miscellaneous Topics – Part 4

Programmatically looking up Beans

As you may know, you can use Vorpal client to create client side application. I talked about using client side Vorpal here. For the most part, Vorpal client has the same programming model as its server counterpart.

Vorpal relies heavily on CDI for resources; this is not a problem if you’re on the server side, but on the client side you have to lookup the CDI instances yourself. The trick is this is to get a reference to either BeanManager or WeldContainer.

Which of those 2 objects you get depends largely on how you bootstrap CDI in the Java SE environment. See this for the various ways. Since BeanManager is standard Java EE API, we’ll use BeanManager.

One way that I’ve found that works is to get CDI to inject an instance of BeanManager by listening to the container starting up event. Then you can cache a reference of BeanManager in a singleton. The following shows how we go about doing this

@ApplicationScoped

public class MySingletons {

   @Inject private BeanManager bm;

   @Inject ComponentContext ctx;

  

   private static MySingletons instance = null;

  

   @PostConstruct private void init() {

      instance = this;

   }

   private void containerInitialized(

         @ObservesContainerInitialized ciEvt) { }

   public BeanManager getBeanManager() {

      return (bm);

   }

   public ComponentContext getComponentContext() {

      return (ctx);

   }

   public static MySingletons getInstance() {

      return (instance);

   }

}

During container startup we use MySingletons to listen to the container initializing and use this opportunity to hold a reference to BeanManager. Same with ComponentContext. Now wherever you need to access either BeanManager or ComponentContext, you can use the static method MySingletons.getInstance() .

Note: Vorpal client is suppose to be CDI implementation agnostic, but I’ve only ever tested it with Weld.

Client side conversation setup

When you’re working with conversation on the client side, you have make sure that you are not working with conversation artifacts from a previous processing cycle.

On the server, before Vorpal calls your message handler, it initializes the component context and populate it with the appropriate bindings and meta data that your message handler will need to process a message correctly. Server side is mostly reactive processing to incoming messages and Vorpal uses this behaviour to perform a lot of mundane task under the hood.

However on the client side, message processing is mostly proactive viz. you click on a button and your application uses Vorpal client to send out a message. Since there is no initializing the component context; you may actually be picking up artifacts from the previous processing cycle. What you have to do is to clear the component context before you perform your processing by calling ComponentContext.startProcessingCycle().

The following code shows you how you clear the component context on every button click

public void actionPerformed(ActionEvent aEvt) {

   String cmd = aEvt.getActionCommand();

   switch (cmd) {

      case “New Conversation”:

         ComponentContext compCtx = MySingletons

               .getInstance().getComponentContext();

         compCtx.startProcessingCycle();

         Conversation conv = lookup(Conversation.class

               , new NamedQualifier(“__conversation__”));

         ConversationContext convCtx = lookup(

               ConversationContext.class);

         conv.begin();

         ResponseContext respCtx =

               new ResponseContext(…);

                    

         compCtx.send(respCtx);

         break;

      …

   }

}

private <T> T lookup(Class<T> type

      , Annotation… qualifiers) {

   T instance = null;

   BeanManager bm = MySingletons.getInstance();

   Bean<T> bean = (Bean<T>)bm.resolve(

         bm.getBeans(type, qualifiers));

   if (null != bean) {

      CreationalContext<T> ctx =

            bm.createCreationalContext(bean);

      instance = bean.create(ctx);

   }

   return (instance);

}

The above shows how you can lookup an instance of Conversation and ConversationContext programmatically. I’ll leave the NamedQualifier class as an exercise for the reader. Hint: use AnnotationLiteral

If you’re just interested in just creating a new conversation but not about associating any states with it then you can manually add a ThreadID to ResponseContext like so:

case “ New Conversation”:

   ComponentContext compCtx = MySingletons

         .getInstance().getComponentContext();

   compCtx.startProcessingCycle();

   ResponseContext respCtx = new ResponseContext(…);

   respCtx.add(ThreadID.generate());

       …

   compCtx.send(respCtx);

   break;

which is a lot simpler. I’ve blog about this in my previously.

Warning: you should not use ComponentContext.startProcessingCycle() when you are developing server side components or bad things will happen.

Turning off conversation inheritance

Vorpal allows conversation states to be inherited viz. if you create a new conversation in the context of an existing conversation, then that new conversation will inherit all the states from the existing ConversationContext.

If you want to suppress the new conversation from inheriting the states, add a property call com.kenai.jabberwocky.framework.property.inheritConversationContext to the existing conversation’s ComponentContext and set the value to false. This will prevent new conversation from inheriting the existing conversation’s state.

//ConversationContext from an existing conversation

convCtx.setAttribute(

      FrameworkProperty.INHERIT_CONVERSATION_CONTEXT

      , false);

//Outgoing packet will not inherit conversation states

ResponseContext respCtx = new ResponseContext(…);

respCtx.add(ThreadID.generate());

   …

compCtx.send(respCtx);

The com.kenai.jabberwocky.framework.property.inheritConversationContext is not a permanent attribute as it is cleared after every processing cycle. So you will have to set it again on the next processing cycle if you wish to further suppress conversation inheritance.

The September 2012 bundles supports the latest conversation features. You can download them here. I’ve just uploaded a new bundle with bug fixes.

Till next time.

Art of Conversation – Part 1

It has been a while since my last blog. A combination of work and reimagining conversation support led to this hiatus. After the last blog, I wanted to do a series on the applicational aspect of Vorpal viz. how do you go about using the various features in Vorpal to implement a custom XMPP service. However I found IQ support wanting; in particular correlating IQ request/response to be really tedious. I’ve also felt, for quite sometime now, that my initial design for conversation support which I blog about here to be extremely simplistic. So I took the opportunity to redesign these.
The good news is that if you are using previous version of Vorpal to develop your application, nothing apparent have change; everything should works as is. If you have any issues, please open an issue or post your problem in the forum. Bad news? Conversation support is quite tricky because it affects the framework greatly so if you find any NPE which wasn’t in earlier releases of Vorpal, please let me know.
Rather than writing a long blog on conversation, I’m going to break this subject into 3 or 4 blogs convering concepts, implicit and explicit conversations and interactions between these.

What are Conversations?

What is the purpose of conversation? Simply put conversation allows a Vorpal application to keep states about an interaction between 2 jabber entity. This is very similar to HTTP session support using HttpSession. In Vorpal states can be kept in ConversationContext, very similiar to HttpSession, and/or in stateful objects marked with @Conversation (think Stateful Session Bean). Every conversation is marked with a unique conversation id.
The default conversation provider gets the conversation id from the following 
  • when there is a <thread> element in <message>. This is part of the XMPP standard. See XEP-0201.
  • or by using implied conversation id support between any 2 Jabber entities when <thread> element is missing. 
All packet falling under the same conversation (viz. having the same conversation id) will be able to access to the same state information stored in ConversationContext or @Conversation message handlers.
The way implied conversation id works is by examining the to or from of a packet and figure out a thread id from there. Vorpal will first look for 
  • conversation between an entity and a chat room (ok an entity as well). It does this by looking for the following pattern ‘@conference.‘ in either the from or to. If it finds it then Vorpal can use the chat rooms JID as a conversation id
  • if the interaction is not with a chat room, then Vorpal will sort the full JID of to and from of a packet and concatenate them giving us a unique conversation id
The advantage of implied conversation id over those explicity marked with <thread> element is that implied conversation supports all 3 types of packets (message, iq and presence) whereas <thread> is only supported in message. The down side of it is that because its implied viz we compute the conversation id using information from the packet, you are really at the mercy of this algorithmn and have no control over the conversation states.

Conversation Types

Vorpal supports 2 types of conversation:
  1. implicit conversation – these are for a request response cycle; they are started automatically started automatically when you send IQ (get/set) packets and are terminated automatically when the corresponding IQ response (result/error) is received or vice versa
  2. explicit conversations – these are conversations that are started by the service by calling Conversation.begin(). Under certain situation explicit conversations are also started automatically; however you must terminate the conversation. We’ll look at this in a future blog (of this series)

Conversation Examples from the Playground

I’ll go into the nitty gritty details of conversation in my next blog. For the impatient, have a look at Eliza in playground. It contains 2 Netbeans project;
  • ElizaService is the external component that implements Eliza. I got the source here. To run it you need to define ‘arkham’ as a subdomain in your XMPP server and the shared secret is ‘ICannotSleep’. Or you can change the deployment settings
  • Arkham is a Java Eliza client
Deploy ElizaService to Glassfish with Jabberocky. To verify that Eliza has been deployed successfully run a discovery service on it. The following screenshot from Gajim shows Eliza service.
There are 2 ways of accessing Eliza. 
  1. The first is to use a standard XMPP client like Gajim. Create a chat room (muc). Then send a direct invitation to eliza@arkham.your_domain. Once Eliza has joined the chat room it will send a greeting to the root. Now you can interact with it by telling Eliza your problem. To end the therapy session, simply type quit or bye
  2. The second is to use Arkham which essentially does the same thing as 1 above. The only difference is that it will initiate a search of for the Eliza service first on the server before connecting. If it cannot find the service, it’ll notify you. Arkham uses client side Vorpal
Eliza shows how to use the client and the server to create a virtual conversation; I’ll be talking about this in greater detail in my next few blogs.
For those who want to check out these new features please download the latest from here. If you have downloaded the package prior to July 29 2012, please download it again. 
Note: I’m trying to get a hang Blogilo after I’ve decided to change from ScribeFire. So you’ll have to excuse me if there are any issues with formatting, etc.
Till next time

Yet Another XMPP Client Library


Vorpal framework is an external component framework. You use it to build services to be delivered by your XMPP server. It occurred to me that I could use the same programming model for client connections viz. like Smack. So now let me introduce Vorpal Client.

Vorpal Client is a Java XMPP library that allows you to connect to an XMPP server; the framework can be used in 3 different ways depending on how much control you want to have.

  1. Implement the com.kenai.jabberwocky.framework.client.ClientComponent interface
  2. Extend the com.kenai.jabberwocky.framework.client.AbstractClientComponent class. The first and second method is very similar to Tinder where you either implement org.xmpp.component.Component or extend org.xmpp.component.AbstractComponent. These methods are quite low level in that you manipulate the XMPP packets directly.
  3. The third is to use CDI, like Vorpal. For the rest of this blog, we will be focusing on this third method. This mode uses the same programming model as Vorpal; the big difference is that whereas Vorpal runs in a container (GlassFish), Vorpal Client runs in an SE environment so there is a little bit of setup involved.

Lets look at the steps to create a simple application that connects to OpenFire (I’ll leave GoogleTalk as an exercise for the reader) using method 3 above.

Create a Configuration File

<connection port=”5222″ domain=”batcomputer”>
   <component-class name=”com.kenai.jabberwocky.framework.client.JabberwockyClientComponent”/>
   <classes-root>classes</classes-root>
   <packages>
      <package name=”com.acme.xmpp.client”/>
   </packages>
   <properties>
      <property
name=”vorpal.component.description” value=”A component to query the customer’s database”/>
      <property
name=”vorpal.component.name” value=”Customer Query Client”/>
   </properties>
</connection>

A few salient points regarding the configuration file

  1. The <connection> starts the configuration. You specify the XMPP server in domain attribute. port attribute is optional and will default to 5222.
  2. After specifying the connection, you now define the client component. If you’re using method 3, then you just use copy the line above.
  3. The <classes-root> and <packages> tells Vorpal Client where to look for your classes (annotated with @Message, @IQ and @Presence) and what packages it should scan. You only have to specify either <classes-root> or <packages>. .
  4. Finally you can specify properties for your components.

Create a Startup Class

Note: If you are not familiar with using CDI (Weld) in Java SE, have a look at this document before proceeding.

We need to first create a startup class.

public class Startup {
   //Inject the command line arguments
   @Inject @Parameters List<String> args;
   //Called when container starts up, like psv main()
   private void initialize(@Observes ContainerInitialized containerEvt) {
      …
   }
}

Next create a main class like so

public class Main {
   public static void main(String[] args) {
      new StartMain(args).go();
   }
}

StartMain is part of Weld SE environment. So you will need to download Weld and add weld-se.jar into your CLASSPATH. Compile the class and bundle it into a JAR file (myclient.jar). Don’t forget to add beans.xml in the META-INF directory.

To run it type the following

java -cp ${CLASSPATH}:myclient.jar Main jabberid password

Creating Connection using Vorpal Client

The following code snippet shows how to create a connection to XMPP server

public class Startup {
   //Inject the command line arguments
   @Inject @Parameters List<String> args;
   //Inject a client connection
   @Inject ClientConnection connection;

   //Called when container starts up, like psv main()
   private void initialize(@Observes ContainerInitialized containerEvt) {
      //Exceptions omitted
      //Read the configuration – see above
      ClientComponentConfiguration config = ClientComponentConfiguration.read(new File(“client.xml”));

      //Connect to the server specified in the config file
      connection = connection.connect(config);

      //Login to the server
      if (!connection.login(args.get(0), args.get(1)) {

         System.err.println(“Authentication failed!”);
         System.exit(-1);
      }
      //Create the application
      connection.createApplication(config);

   }
}

Some salient points regarding the code snippet from above

  • You can create ClientConnection manually by specifying the server and port; see javadoc. But if you are planning to get access to the ClientConnection object in other parts of your application, then its better to use CDI injection. The injected ClientConnection is application scoped so you’ll get the same object throughout your application. The current release does not supported @Named ClientConnections. @Named will allow the support of more than one injected connection. This is currently a very low priority cause I’m not sure if anyone will use more than 1 connection.
  • Next we read in the application’s configuration and use that to initialize the connection. Invoking connect() causes the connection to connect to the XMPP server.
  • Following that, we login to the server. Username and password is not part of the configuration so you have to somehow pass that in. In the example above, we pass it in through the command line. If the authentication fails, login() will return false
  • Finally we call createApplication() to create and start the application.

Initializing Your Application

Once you have got past the createApplication(), you can now start your application using Vorpal’s lifecycle events.

private void postComponentStart(@Observes ComponentPostStart postStartEvent) {
   //Exceptions omitted
   ResponseContext respContext = new ResponseContext();
   respContext.type(
ResponseContext.Type.Presence)
         .add(“I’m online”)
         .add(Presence.Show.chat);
   postStartEvent.getComponentContext.send(respContext);
}

In the example code above, after the ComponentPostStart event, we send a presence message using response context (see this if you are unfamiliar with response context). For Vorpal Client, if you do not fill in the to() and from() in the response context, then they will default to the server that your client is connect to and the Jabber ID that you’ve used to login respectively. There is also a new predefined binding call __self__. __self__ will give you the full JID of the Jabber ID that is used to login. For an application to find out what is the id that is used to login, you can do this

@Inject @Named(“__self__”) JID me;

While we are on this topic, __subdomain__ will return null and __domain__ will return the Jabber server that the application is connected to. There are also a few new annotations @Identity, @Feature and @Item to match disco#info and disco#items.

Your application can respond to incoming message in the same way that you are using Vorpal viz. their programming model is exactly the same so I won’t repeat it here. You can find an introduction to Vorpal programming model here.

Running the Application

The bad news is that Vorpal Client uses a quite a lot of external JARs. The good news is that most of these are already bundle for Jabberwocky. So lets assume that your application JAR is call myclient.jar, then this is how you run it

java -cp myclient.jar:vorpal.jar:weld-se.jar:jabberwocky_support.jar my.main.Class

You can get vorap.jar and jabberwocky_support.jar from the framework bundle. weld-se.jar from Weld download (use Weld 1.1). Please note that jabberwocky_support.jar MUST BE LAST JAR in the -cp switch because of this issue.

I have a full blown Vorpal Client application here if you need more example. The QueryClient complements the CustomerQuery; the source can be found here.

Vorpal Client currently is still considered experimental and does not support features like compression SSL, etc.

The latest bundle that supports Vorpal Client can be found here. There are lots of bug fixes to the Vorpal framework especially if you’re using CDI. So please upgrade to this release.

I’m keen to hear what you think of Vorpal Client as I’ve big plans for it. The really nice thing about it is that any feature that I add to the client can also be used in the ‘server’ portion. 

Till next time.

%d bloggers like this: