Mark Derricutt's Disturbing Thoughts

Writing XMPP Transports in Java

posted Friday, 16 July 2004
The other week someone in jdev was asking about writing transports in Java and I've been meaning to write up some example code here, the Jabber/XMPP transport code was written using the Marbles framework.  The SMS code ( which seems to generate more interest than the XMPP side of things ) simply uses $EMPLOYER's SOAP gateway, this means that theres actually very little code in the transport itself - its pretty much just glue. At the heard of a Marbles based transport is the ComponentConnection class and ComponentConnectionEventListener interface, when your application starts you connect to a jabber server by connecting to the server and attaching our listener:
ComponentConnectionInfo connect_info = new ComponentConnectionInfo(
    APPLICATION_NAME,
    "localhost",  // Hostname of Jabber Server
    "secret",     // Secret/password to connect to server
    "jabber:component:" + APPLICATION_NAME,
    8002,         // Port to connect to
    true);

ComponentConnection connection = new ComponentConnection(new MyTransportHandler(), connect_info);
The MyTransportHandler class implements a somewhat basic interface that simply routes DOM Elements:
public interface ComponentConnectionEventListener { 
    void onActive();  
    void onConfig(Element element);  
    void onPacket(Element element); 
}
A simple implementation of onPacket() to print incoming messages to the console works as follows:
public void onPacket(Element element) {
    // We're very simple here, we only handle messages, not chats
    if ( element.getNodeName().equals("message") ) {
        // We're also only interested in non-error messages
        if (element.getAttribute("type") == null || (!element.getAttribute("type").equals("error"))) { 
            try { 
                String from = element.getAttribute("from");
                String to = element.getAttribute("to");

                // Loop children of the message and look for the body
                NodeList childList = element.getChildNodes(); 
                String body = ""; 
                for ( int i = 0; i < childList.getLength(); i++ ) { 
                    Node node = childList.item(i); 
                    if ( node.getNodeName().equals("body")) { 
                        body = node.getChildNodes().item(0).getNodeValue(); 
                    }
                }

                System.out.println("Jabber message from " + from + " to " + to + ": " + body);
            } catch (Exception e) { 
                e.printStackTrace();
            } 
        }
    } 
}
So the code doesn't do much, but once you've got XMPP messages coming into your code, you're free to bounce it into what ever other layer you want to implement, in the case of using $EMPLOYERS SMS gateway, all I did was:
// Find SMS Gateway WebService
BulletinServerProxy proxy = BulletinServerProxyLocator.getBulletinServerProxy();
BulletinMessage message = getMessageFromElement(element);
proxy.send(BulletinConnectComponent.APPLICATION_NAME, 1, message );

// Store message in database
recordMessageHistory(from, message);
Now that we have this funky java based XMPP transport running we need a Jabber server to connect to, under jabberd 1.4 two entries in jabber.xml are required, the first inside the sessions service element:
<service type="sms" jid="sms.yourhost" name="Some Descriptive name">
    <ns>jabber:iq:gateway</ns>
    <ns>jabber:iq:register</ns>
</service>
and the second in its own <service> element:
<service id="bcjab">
    <host>sms.yourhost</host>
    <accept>
        <ip>127.0.0.1</ip>
        <port>8002</port>
        <secret>secret</secret>
    </accept>
</service>
Simply match up the APPLICATION_NAME to the service id, ip, port, and secret with the ComponentConnectionInfo in the transport and you're away laughing, or at least away debugging.

links: digg this    del.icio.us    technorati    reddit