Google App Engine for JavaでXMPPを使ってみる
XMPPとはGTalkなどで使われているXMLベースのプロトコル。そして、Google App Engineからも使えるようにAPIが提供されているらしいので試しに使ってみた。
http://code.google.com/intl/ja/appengine/docs/java/xmpp/overview.html
GAEで作ったアプリからメッセージを送信することも出きるし、受信することもできる。そして、今回ためしに作ってみたのはGtalkでメッセージを送ったらそれに対する返事をするという人工知能アプリだ。(最後のはうそ)
受信に使われるJID(XMPPの中で使われるアドレス)は
- app-id@appspot.com
となる。app-idはアプリケーションのIDのこと(appengine-web.xmlに書いているアレ)そして、カスタムのアドレスも作れるみたいで、その場合は
- anything@app-id.appspotchat.com
となり、anythingの部分は好きな文字を入れてよい。このアドレスへメッセージを投げても受け取る先は同じ。GAEは送信者のアドレスを選んで送信することができる。(ドキュメントにドメイン違うから注意って書いてたのに間違った。ドメインの部分にapp-idが付いただけじゃなくその後も「appspotchat.com」なんだね。)
さて、今回のアプリを作って動かすまでにやることはざっと以下の6つ
- appengine-web.xmlにXMPPでメッセージを受信できるように設定
- 普通のHttpServletを継承したクラスを作成(これがメッセージを受信したときに動く)
- web.xmlに2で作成したServletを登録
- appspotにデプロイ
- Gtalkからapp-id@appspot.comを招待する。
- Gtalkからapp-id@appspot.com宛にメッセージを投げると返事が返ってくる。
1. ppengine-web.xmlにXMPPでメッセージを受信できるように設定
以下の行を追加します
<inbound-services> <service>xmpp_message</service> </inbound-services>
これは、applicationタグやversionタグと同じレベルに追加します。
2. 普通のHttpServletを継承したクラスを作成(これがメッセージを受信したときに動く)
こんな感じ。
package sample.controller.xmpp; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.appengine.api.xmpp.JID; import com.google.appengine.api.xmpp.Message; import com.google.appengine.api.xmpp.MessageBuilder; import com.google.appengine.api.xmpp.SendResponse; import com.google.appengine.api.xmpp.XMPPService; import com.google.appengine.api.xmpp.XMPPServiceFactory; @SuppressWarnings("serial") public class XMPPReceiverServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { XMPPService xmpp = XMPPServiceFactory.getXMPPService(); Message message = xmpp.parseMessage(req); // メッセージを受け取った JID fromJid = message.getFromJid(); String body = message.getBody(); // 返事を返す String msgBody = "...zzz"; if ("hello".equals(body)) { msgBody = "Hello " + message.getFromJid(); } else if ("かっこいいね".equals(body)) { msgBody = "でしょー"; } Message msg = new MessageBuilder() .withRecipientJids(fromJid) .withBody(msgBody) .build(); boolean messageSent = false; if (xmpp.getPresence(fromJid).isAvailable()) { SendResponse status = xmpp.sendMessage(msg); messageSent = status.getStatusMap().get(fromJid) == SendResponse.Status.SUCCESS; } if (messageSent) { System.out.println("メッセージを送信しました"); } else { System.out.println("メッセージの送信に失敗しました"); } } }
xmpp.parseMessage(req);の部分でHttpServletRequestからメッセージ内容を解析してcom.google.appengine.api.xmpp.Messageに変換しています。それこからメッセージボディの内容をみて、どんなメッセージを送り返すか決めてます。その後、送信するためにメッセージを生成して、xmpp.sendMessage(msg)でメッセージ送信者に送り返します。
3. web.xmlに2で作成したServletを登録
こんな感じ。
<servlet> <servlet-name>xmppreceiver</servlet-name> <servlet-class>sample.controller.xmpp.XMPPReceiverServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>xmppreceiver</servlet-name> <url-pattern>/_ah/xmpp/message/chat/</url-pattern> </servlet-mapping>
app-id@appspot.comに送られたメッセージは「/_ah/xmpp/message/chat/」ここにくることになっているようです。なので、url-patternはこうなっています。
4. appspotにデプロイ
デプロイします。ローカル環境ではメッセージの送受信は実際には行うことが出来ません。送信してもコンソールにメッセージの内容が出てくるだけで寂しいです。
5. Gtalkからapp-id@appspot.comを招待する。
今デプロイしたアプリのJID(app-id@appspot.com)を招待します。招待したらアプリは勝手に承認するので、特にやることはないです。すぐにapp-id@appspot.comがオンライン状態になって現れるはずです。
6. Gtalkからapp-id@appspot.com宛にメッセージを投げると返事が返ってくる。
そして、Gtalkからapp-id@appspot.com宛にメッセージを投げてみましょう。こんな感じで人工知能らしからぬ反応が返ってきますよっと。
me: hello app-id: Hello <JID: aaaaaa@gmail.com/gmail.xxxxxx> me: かっこいいね app-id u: でしょー
いや、簡単。これはおもしろい。これだけでおもしろいアプリが出来そうだね。でも、俺アイディアないからなかなかアレだけど。何か作りたくなるそんなXMPPでした。
ローカルでテスト
あと、ローカルでテストするには以下のURLにアクセスしXMPPメッセージを送信することが出来ます。
このアプリをテストするにはFromとToに「app-id@appspot.com」を入力、メッセージも適当に入力して「送信」を押します。するとServletが呼ばれて以下のような感じでコンソールにログが出力されます。ローカルではこの内容を取得してチェックするのかな。送られたメッセージはテストの時取得できるのかなー。
Sending an XMPP Message: Body: Hello <JID: app-id@appspot.com> Type: chat RawXml: false To JIDs: app-id@appspot.com メッセージを送信しました