Overview of XMPP API for Java

An App Engine application can send and receive chat messages to and from any XMPP-compatible chat messaging service. An app can send and receive chat messages, send chat invites, request a user's chat presence and status, and provide a chat status. Incoming XMPP messages are handled by request handlers, similar to web requests.

Some possible uses of chat messages include automated chat participants ("chat bots"), chat notifications, and chat interfaces to services. A rich client with a connection to an XMPP server can use XMPP to interact with an App Engine application in real time, including receiving messages initiated by the app.

Currently, an app cannot participate in group chats. An app can only receive messages of types "chat" and "normal". An app can send messages of any type defined in RFC 3921.

Sending chat messages

An app can send chat messages to any XMPP address by calling the XMPP service API. A chat message can be of any of the five types defined in RFC 3921. Note that an app can only receive two types of messages:

  1. Chat messages via /_ah/xmpp/message/chat/
  2. Normal messages via /_ah/xmpp/message/chat/

For the body of the message, an app can provide plain text that is displayed to the user, or it can provide an XML stanza that is included in the XMPP XML data. You can use XML message data to communicate structured data to a custom client.

The following example tests for a user's availability, then sends a chat message.

@SuppressWarnings("serial")
public class MessageSenderServlet extends HttpServlet {
  private static final Logger log = Logger.getLogger(MessageSenderServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse res)
      throws IOException {

    JID jid = new JID("example@gmail.com");
    String msgBody = "Someone has sent you a gift on Example.com. To view: http://example.com/gifts/";
    Message msg =
        new MessageBuilder()
            .withRecipientJids(jid)
            .withBody(msgBody)
            .build();

    boolean messageSent = false;
    XMPPService xmpp = XMPPServiceFactory.getXMPPService();
    SendResponse status = xmpp.sendMessage(msg);
    messageSent = (status.getStatusMap().get(jid) == SendResponse.Status.SUCCESS);

    log.info("Message sent? " + messageSent);

    if (!messageSent) {
      // Send an email message instead...
    }
  }
}

When an app running in the development server sends an XMPP message, the fields of the message are printed to the console, and no message is sent. The development server cannot send XMPP messages on behalf of the app.

Handling incoming calls

App Engine provides three inbound services to manage messages, subscriptions, and presence:

  • xmpp_message allows your application to receive chat messages from XMPP-compliant chat services.
  • xmpp_subscribe allows subscriptions between users and your application for the purpose of exchanging data, such as chat messages, presence information, and status messages.
  • xmpp_presence allows your application to determine a user's chat presence (available or unavailable).
  • xmpp_error allows your application to receive error stanzas.

You can enable these inbound services in appengine-web.xml:

<inbound-services>
  <service>xmpp_message</service>
  <service>xmpp_presence</service>
  <service>xmpp_subscribe</service>
  <service>xmpp_error</service>
</inbound-services>

The following sections show you how to handle these inbound services in your application:

Receiving chat messages

Users of XMPP-compliant chat services can send chat messages to App Engine applications. For an app to receive chat messages, the XMPP message service must be enabled in the app's configuration.

To enable the XMPP service for a Java app, edit the appengine-web.xml file and include the following lines:

<inbound-services>
  <service>xmpp_message</service>
</inbound-services>

With the XMPP service enabled, App Engine makes an HTTP POST request to the following URL path when your app receives a chat message:

/_ah/xmpp/message/chat/

To handle incoming messages, you simply create a request handler that accepts POST requests at this URL path.

This URL path is restricted to app administrators automatically. The XMPP service connects to the app with "administrator" status for the purposes of accessing this URL path. You can configure the path to have this restriction explicitly if you like, but this is not necessary. Only the XMPP service and clients authenticated as administrators using Google Accounts can access this URL path.

The POST request data represents the message as a MIME multipart message (RFC 2388). Each part is a named POST parameter:

  • from, the address of the sender of the message
  • to, the address of the recipient as described by the sender (see below)
  • body, the body of the message
  • stanza, the full XMPP message in its original XML form

An app can receive messages of two XMPP types: "chat" and "normal." If App Engine receives an XMPP message of an unsupported type, the message is ignored and the request handler is not called.

The Java Servlet API does not provide a way to parse MIME multipart POST data directly. The XMPP API includes a helper method for parsing this data from the HttpServletRequest object. The following example illustrates how to use this helper class to parse incoming XMPP messages.

@SuppressWarnings("serial")
public class MessageReceiverServlet extends HttpServlet {
  private static final Logger log = Logger.getLogger(MessageReceiverServlet.class.getName());

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse res)
      throws IOException {

    XMPPService xmpp = XMPPServiceFactory.getXMPPService();
    Message message = xmpp.parseMessage(req);

    JID fromJid = message.getFromJid();
    String body = message.getBody();

    log.info("Received a message with id: " + fromJid + " and body: " + body);
    // ...
  }
}

To map this servlet to the XMPP URL path, put the following section in your web.xml file, inside the <web-app> element:

<servlet>
  <servlet-name>messagereceiver</servlet-name>
  <servlet-class>com.example.appengine.xmpp.MessageReceiverServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>messagereceiver</servlet-name>
  <url-pattern>/_ah/xmpp/message/chat/</url-pattern>
</servlet-mapping>
<servlet>

Handling subscriptions

Enabling the xmpp_subscribe inbound service allows your application to receive updates to a user's subscription information via POSTs to the following URL paths:

  • POSTs to /_ah/xmpp/subscription/subscribe/ signal that the user wishes to subscribe to the application's presence.
  • POSTs to /_ah/xmpp/subscription/subscribed/ signal that the user has allowed the application to receive its presence.
  • POSTs to /_ah/xmpp/subscription/unsubscribe/ signal that the user is unsubscribing from the application's presence.
  • POSTs to /_ah/xmpp/subscription/unsubscribed/ signal that the user has denied the application's subscription request, or cancelled a previously granted subscription.

These URLs correspond to the stanzas used for managing subscriptions described in the XMPP Instant Messages and Presence Protocol.

The following code sample demonstrates how to track subscriptions using webhooks to the above handlers. The following code sample uses POSTs to the above handlers to maintain a roster of subscribed users in the datastore:

@SuppressWarnings("serial")
public class SubscriptionServlet extends HttpServlet {
  private static final Logger log = Logger.getLogger(SubscriptionServlet.class.getName());

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse res)
        throws IOException {
    XMPPService xmppService = XMPPServiceFactory.getXMPPService();
    Subscription sub = xmppService.parseSubscription(req);

    // Split the bare XMPP address (e.g., user@gmail.com)
    // from the resource (e.g., gmail.CD6EBC4A)
    String from = sub.getFromJid().getId().split("/")[0];

    log.info("Received subscription event from: " + from);
  }
}

Handling user presence

Enabling the xmpp_presence inbound service allows your application to detect changes to a user's chat presence. When you enable xmpp_presence, your application receives POSTs to the following URL paths:

  • POSTs to /_ah/xmpp/presence/available/ signal that the user is available and provide the user's chat status.
  • POSTs to /_ah/xmpp/presence/unava