[UPDATED] XMPPPool : XMPP Connection Pooling for Tomcat and Grails/Jetty

Release 0.3 of XMPPPool

[Update : also added support for Grails Jetty]

[Update 2 : Simplified the API a lot. It is now basically invisible …]

About

It provides XMPP connection pooling for Tomcat, configured as a resource in the $TOMCAT_HOME/conf/server.xml.

The main use case to use Groovy Jabber-RPC, with the webapp acting as a client :

  • You fetch a XMPPConnection from the pool,
  • call an RPC method,
  • get the result,
  • return the XMPPConnection to the pool.

Of course you can use the code to write XMPP “servers”/bots, but you’ll have to manage the lifecycle of the connection (i.e. launch a separate thread)

How it works

A pool is created, with connections to the XMPP server. All connections use the same XMPP account, but each have a unique resource.

Rule 10.5 of RFC 3920 (XMPP Core) means that is a stanza is sent to a JID with a specific resource, it MUST be delivered to this resource or it MUST fail.
However if a stanza is sent to a jid without any resource identifier, it SHOULD be sent to at least one of the resources.

So make sure that the code answering to a query coming from an XMPPPool managed connection sends it to a specific JID.

Quick install guide for Tomcat

Download XMPPPool-0.3.0-jar-with-dependencies.jar.zip and copy it in your $TOMCAT_HOME/common/lib.
Then in server.xml, configure your source as follow :


<Resource auth="Container" maxActive="10" maxIdle="5" maxWait="10000"
  factory="com.ohmforce.xmpp.XMPPSourceFactory" type="com.ohmforce.xmpp.XMPPConnectionPool" name="xmpp/connection"
  username="username" password="pass" service="localhost" port="5222"/>

The pooling code is using commons-pool from Apache. All the usual options are available. port is optional and defaults to 5222.

Now restart your container.

Quick install guide for Grails/Jetty

First you need to patch Grails as per this report (which should be implemented soon in Grails). Don’t forget to add the jars to $GRAILS_HOME/lib!

Also unzip and add XMPPPool-0.3.0-jar-with-dependencies.jar in GRAILS_HOME/lib

Then add a jetty-env.xml file in WEB-INF/ directory (of your Grails app)


<Configure class="org.mortbay.jetty.webapp.WebAppContext">
  <New id="xmpp" class="org.mortbay.jetty.plus.naming.Resource">
    <Arg>xmpp/connection</Arg>
    <Arg>
    <New class="com.ohmforce.xmpp.XMPPSourceFactory">
     <Set name="properties">
       <New class="java.util.Properties">
         <Put name="username">username</Put>
         <Put name="password">pass</Put>
         <Put name="service">localhost</Put>
       </New>
      </Set>
   </New>
 </Arg>
   </New>
</Configure>

Start the grails app : grails -Denable.jndi=true run-app

Now inside a grails controller you can connect to a Jabber-RPC service :

Using from Grails :

Now inside a grails controller you can connect to a Jabber-RPC service :


import javax.naming.InitialContext;
import groovy.net.xmlrpc.*
class HelloController{
def hello = {
        def p =new InitialContext().lookup("java:comp/env/xmpp/connection")
        def serverProxy = new JabberRPCServerProxy(p, "cstar@localhost")
        def s = serverProxy.add(2,6)
        def e = serverProxy.echo("toto")
        flash.message = "${s} and ${e}"
        p.disconnect() // does not actually disconnect, but returns connection in pool
    }
}

The server code (slightly modified from the examples on the Groovy website. fixed typos and updated to latest Smack version) :


import groovy.net.xmlrpc.*
import org.jivesoftware.smack.XMPPConnection
def server = new JabberRPCServer()
server.echo = {return it+"toto"}
server.add = {i,j -> return i+j}
def serverConnection = new XMPPConnection("localhost")
serverConnection.connect()
serverConnection.login("user", "pass")
server.startServer(serverConnection)

Using the datasource in a servlet


try{
    InitialContext ctx = new InitialContext();
    XMPPConnection conn = (XMPPConnection) ctx.lookup("java:/comp/env/xmpp/connection");
    // Do things here
    conn.disconnect(); // does not actually disconnect, but returns connection in pool
}
catch(Exception e){
    e.printStackTrace();
}

For actually using the connection, please refer to the Smack developper guide

Building the source code

The project is built with Maven.

mvn assembly:assembly

cp target/XMPPPool-0.3.0-jar-with-dependencies.jar $TOMCAT_HOME/common/lib/

And you’re set.

Bugs ? Patches ?

  • mail : eric at ohmforce dot com
  • xmpp : cstar at cestari dot info

Known issues

  • Only one pool can be configured on a given tomcat instance (Although that should fit most use cases)

Todo

  • Better error reporting, I guess🙂

License

Apache 2.0 license, the same as Smack and others libs XMPPPool is built upon. Free to use, as long as you don’t sue me or remove my name from the code …

Download

1 comment so far

  1. hutch on

    First off, nice work — this does 90 percent of what I need invisibly.

    I’m running into an issue on tomcat 6.014 where I get a stack overflow exception — but it doesn’t happen right away. Only after about requests to the servlet (so about 20 pooled connections taken and returned).

    I looks like it’s happening when I call disconnect() on a XMPPPooledConnection. I’m thinking that might have to do with XMPPPooledConnection.disconnect trying to call super.disconnect from what I see in the stack trace.

    I’m going through the source now and will let you know if I track it down. Meanwhile, any ideas?


Comments are closed.

%d bloggers like this: