Episode 2 : Update : Communicating to another XMPP Account via your Bot

I received a good comment on my second post, where we saw how to write your own XMPP Bot and deploying it on the Google App Engine for Java (GAEJ).

It asked whether one can communicate to another Jabber account from the XMPP Bot hosted on the GAEJ. The confusion arose because I covered the usage of Google Talk, which is an IM client itself. And it looked from my post that you can only use Google Talk as the client to talk the XMPP agent that you wrote.

The short answer is that yes, even if you are using another Instant Messaging (IM) client like Spark or Pidgin, it is possible to communicate to the XMPP bot that you have written and which is running inside the GAEJ cloud.

However, it turned out that I made a mistake in writing the code for the XMPP bot. The Google App Engine XMPP documentation clearly states that you can communicate to any other Jabber ID but it is not possible for their infrastructure to check for the presence of a Jabber ID on another network except their Google Talk network. This is fair enough. By presence, we are simply trying to see if the user is online or not.

So , we had some code in our XMPP bot that we saw earlier, which went something like this. This code fragment was at the very end when we are sending back the echo for our Agent.

if (xmpp.getPresence(fromJid).isAvailable()) {
SendResponse status = xmpp.sendMessage(replyMessage);
messageSent = (status.getStatusMap().get(fromJid) == SendResponse.Status.SUCCESS);
}

What we are doing here is that we are checking for the presence of another JabberID i.e. making sure that is online before sending the message. This works fine on the Google Network but not on other XMPP Networks like Jabber.org. So for e.g. our bot Jabber Id was gaejxmpptutorial@appspot.com. And if the Jabber Id which is talking to it is someid@jabber.org, then it will not be possible for your bot running inside of the Google network to determine if someid@jabber.org is online or not. As a result of this, the code will never enter the block and the message does not get sent.

So, all you have to do to send the message across to another network is to remove the check for the isAvailable() condition and simply call the sendMessage(...) method.

I have verified this by doing the  following:

  1. Used another IM client instead of Google Talk. I used the IM client called Spark
  2. I have an account at jabber.org which I used to login as shown below in the Spark IM client:post4-3
  3. I added gaejxmpptutorial@appspot.com as a contact in Spark IM client.post4-1
  4. I sent a chat message across to the gaejxmpptutorial bot and got back the echo as shown below:post4-2

Hope this clarifies that it is possible to communicate to your bot over XMPP from other XMPP Servers. Let me know if any of you are still having issues and I welcome your comments.

About these ads

About rominirani

Google Developer Expert Cloud 2014. Harnessing the power of software by learning, teaching and developing simple solutions. I love learning about new technologies and teaching it to others.
This entry was posted in Cloud Computing, Google App Engine. Bookmark the permalink.

6 Responses to Episode 2 : Update : Communicating to another XMPP Account via your Bot

  1. asianCoolz says:

    great tutorial. I very enjoy reading it. Right now you are creating gtalk bot inside GAE. My new question is, is it possible to create an external jabber bot inside GAE?

  2. rominirani says:

    I do not think that is possible since the idea is to create a jabber bot inside of GAE.

    If the bot resides outside GAE, then why would you need GAE ? :-)

  3. Pingback: Twitter Trackbacks for Episode 2 : Update : Communicating to another XMPP Account via your Bot « Google App Engine Java Experiments [gaejexperiments.wordpress.com] on Topsy.com

  4. robin bakkerus says:

    Very good tutorial, helped a lot.
    Do you any idea how to test a XMPP messsage on your local development environment.
    As far as I know, there is NO xmpp server running if you start the Webapplication locally. So what is the alternative? running something like OpenFire?

    • rominirani says:

      Hello Robin,

      Thanks for your comments.

      You can test out your XMPP message locally. Follow these steps:
      1) From within Eclipse, Do “Run/Debug As Web Application”. This will launch your application and let us assume that it is running on port 8080.
      2) Now, from a browser, go to the following URL : http://localhost:8080/_ah/admin
      3) This will bring up an Administrative Console from where you can do things like viewing your Data Store. You will also find an option for “XMPP” on the left.
      4) Click that and put in any values for the from and to. And a message that you want to send. Put a breakpoint or some log statements and you will find the messages flowing to and fro in your Eclipse IDE Console.

      While it is not a full fledged replacement — it is more than sufficient to test our your XMPP Bot.

      Hope this helps.

      Thanks
      Romin

      • robin bakkerus says:

        Thank you to point out: _ah/admin.
        I did some experiments, and i figured out another possibility using: OpenFire (xmpp server) and the following xmpp client using the Smack api:


        package flca.test;

        import org.apache.commons.httpclient.HttpClient;
        import org.apache.commons.httpclient.methods.PostMethod;
        import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
        import org.apache.commons.httpclient.methods.multipart.Part;
        import org.apache.commons.httpclient.methods.multipart.StringPart;
        import org.jivesoftware.smack.PacketListener;
        import org.jivesoftware.smack.Roster;
        import org.jivesoftware.smack.RosterEntry;
        import org.jivesoftware.smack.XMPPConnection;
        import org.jivesoftware.smack.XMPPException;
        import org.jivesoftware.smack.filter.AndFilter;
        import org.jivesoftware.smack.filter.PacketFilter;
        import org.jivesoftware.smack.filter.PacketTypeFilter;
        import org.jivesoftware.smack.packet.Message;
        import org.jivesoftware.smack.packet.Packet;

        public class TestSmack {

        /**
        * @param args
        */
        public static void main(String[] args) {
        TestSmack testsmack = new TestSmack();
        testsmack.initialize();
        testsmack.setupListener();

        while (true) {
        try {
        Thread.sleep(5000);
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        System.out.print(".");
        }
        }

        private XMPPConnection connection;

        public void initialize() {
        try {
        connection = new XMPPConnection("localhost");

        // Connect
        connection.connect();

        // Login with appropriate credentials
        connection.login("sean", "jrb1234");

        // Get the user's roster
        Roster roster = connection.getRoster();

        // Print the number of contacts
        System.out.println("Number of contacts: " + roster.getEntryCount());

        // Enumerate all contacts in the user's roster
        for (RosterEntry entry : roster.getEntries()) {
        System.out.println("User: " + entry.getUser());
        }
        } catch (XMPPException e) {
        // Do something better than this!
        e.printStackTrace();
        }

        }

        public void setupListener()
        {
        PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class));

        PacketListener myListener = new PacketListener() {
        public void processPacket(Packet packet) {
        if (packet instanceof Message) {
        Message msg = (Message) packet;
        handleMessage(msg);
        }
        }
        };
        // Register the listener.
        connection.addPacketListener(myListener, filter);
        }

        private void handleMessage(Message aMsg)
        {
        PostMethod method = null;

        try {
        System.out.println("starting handleMessage " + aMsg.getFrom() + " " + aMsg.getTo() + " " + aMsg.getBody());
        HttpClient client = new HttpClient();
        // client.getParams().setParameter("http.useragent", "Test Client");

        Part parts[] = {
        new StringPart("from", aMsg.getFrom()),
        new StringPart("to", aMsg.getTo()),
        new StringPart("body", aMsg.getBody())
        };

        method = new PostMethod("http://localhost:8888/_ah/xmpp/message/chat/");
        method.setRequestEntity(new MultipartRequestEntity(parts, method.getParams()));

        System.out.println("before post");
        int returnCode = client.executeMethod(method);

        System.out.println("returned " + returnCode);

        } catch (Throwable t) {
        System.err.println(t);
        } finally {
        method.releaseConnection();
        }
        }
        }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s