Google Talkの仲間リストを表示する

前回はXMPP対応のJava用IMライブラリである「Smack」を取り上げ、Google Talkに接続してチャットを行うプログラムの例を紹介した。今回は引き続きSmackを用いてGoogle Talkの仲間リストを参照する方法を解説する。

Smackでは仲間リストを扱うためのクラスとしてorg.jivesoftware.smack.Rosterクラスが用意されている(ちなみにSmack APIのクラスの名称や構造は基本的にXMPPの仕様に準じている)。Rosterのインスタンスは、次のようにXMPPConnectionオブジェクトからgetRoster()メソッドを使って取得することができる。

リスト1

XMPPConnection connection = new XMPPConnection(config);
Roster roster = connection.getRoster();

Rosterオブジェクトには複数のorg.jivesoftware.smack.RosterEntryオブジェクトが含まれている。RosterEntryは、仲間リストに登録されているユーザの情報を保持するクラスである。このRosterEntryから、それぞれの仲間のユーザIDや名前、状態などを取得することができる。次のコードは、RosterからRosterEntryのリストを取り出しし、それぞれのRsoterEntryに含まれる情報と状態を表示する例である。RosterEntryの一覧はgetEntries()メソッドで取得できる。

リスト2

Collection<RosterEntry> entries = roster.getEntries();
for (RosterEntry entry : entries) {
    // 仲間の情報を表示
    System.out.println(entry);
    System.out.println("    状態: " + entry.getStatus());
}

仲間についてのより詳細な状態を調べたい場合には、存在情報に関するパケットを扱うorg.jivesoftware.smack.packet.PresencePresenceクラスを利用する。XMPPでは存在情報の通知にPresenceパケットを使用する。Presenceクラスはこのパケットから取得した存在情報を保持するためのものであり、パケットのタイプやモードの情報を持つ。パケットのタイプはどのような存在状態が通知されたかを表すもので、Presence.Typeクラスに以下の値が定義されている。

  • available - メッセージを受信可能な状態(オンライン)
  • unavilable - メッセージが受信不可能な状態になった(オフライン)
  • error - パケットがエラーメッセージを含む
  • subscribe - 承認を申請する
  • subscribed - 承認され、仲間に加わった
  • unsubscribe - 承認の申請が拒絶された
  • unsubscribed - 仲間から外した

Presenceのモードとしては、Presence.Modeクラスに以下の5つが定義されている。これによってオンラインにいる仲間の詳細な状態を知ることができる。

  • available - 在席
  • chat - チャットできる
  • away - 離席中
  • xa (extended away) - 出かけている
  • dnd (do not disturb) - 手が離せない

Presenceオブジェクトは、RosterクラスのgetPresence()メソッドに対して対象となる仲間のユーザIDを渡すことで取得できる。PresenceのタイプはgetType()メソッドで、モードはgetMode()メソッドでそれぞれ取得することが可能。そのほかに、getStatus()メソッドによってステータスメッセージを取得できる。ステータスメッセージには、仲間が設定したメッセージ(たとえば「いま席を外しています」など)が格納されている。次のコードは、"mycom@gmail.com"というユーザの状態を表示する例である。

リスト3

Presence presence = roster.getPresence("mycom@gmail.com");
System.out.println("    存在");
System.out.println("        タイプ: " + presence.getType());
System.out.println("        モード: " + presence.getMode());
System.out.println("        ステータス: " + presence.getStatus());

次に示すRosterSampleは、XMPPサーバにログインして仲間リストを取得して各仲間の存在情報を表示するコードの例である。printRoster()メソッドにおいて、前述の方法で仲間の情報を表示している。

リスト4

public class RosterSample {
    private XMPPConnection connection = null;

    /* サーバへの接続とログイン */
    public void connect(String server, String username, String password) {
    // 前回のサンプルコードと同様なので省略
    }

    /* 仲間リストを表示する */
    public void printRoster() {
        // Rosterオブジェクトを取得
        Roster roster = connection.getRoster();

        // Rosterの各エントリについて
        Collection<RosterEntry> entries = roster.getEntries();
        for (RosterEntry entry : entries) {
            // 仲間の情報を表示
            System.out.println(entry);
            System.out.println("    状態: " + entry.getStatus());

            // 仲間の存在情報を表示
            Presence presence = roster.getPresence(entry.getUser());
            System.out.println("    存在");
            System.out.println("        タイプ: " + presence.getType());
            System.out.println("        モード: " + presence.getMode());
            System.out.println("        ステータス: " + presence.getStatus());
        }
    }

    public static void main(String[] args) {
        RosterSample xmpp = new RosterSample();
        // サーバに接続
        xmpp.connect("gmail.com", "[USERNAME]", "[PASSWORD]");

        // 状態が反映されるまでの時間待ち
        try {
            Thread.sleep(5000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

        // 仲間リストを表示
        xmpp.printRoster();

    // 切断
        xmpp.destroy();
    }
}

サーバに接続するところまでは前回示したコードと同様である。接続に成功したらprintRoster()を呼び出せばいいのだが、状態が反映されるまでに多少時間がかかるため、あえて5秒ほど待ち時間を作っている。このプログラムを実行すると、仲間リストにあらかじめユーザが登録されていれば、次のように仲間の状態が表示される。括弧内に表示されているのはグループ名である。

プロンプト1

太郎さん: xxxxxxxx@gmail.com [マイコミ]
    状態: null
    存在
        タイプ: available
        モード: away
        ステータス:
次郎@google: xxxxxxxx@gmail.com [友人]
    状態: subscribe
    存在
        タイプ: unavailable
        モード: null
        ステータス: null
三郎: xxxxxxxx@gmail.com [仲間]
    状態: null
    存在
        タイプ: available
        モード: away
        ステータス: 出かけています

仲間リストをグループ別に表示する

上記の例で見たように、RosterEntryにはその仲間が所属するグループ名の情報も含まれている。そこで、今度はグループ別の仲間リストを作ってみよう。Rosterクラスには、仲間リストに登録されているグループの一覧を取得する方法としてgetGroups()メソッドが用意されている。このメソッドは、各グループの情報を保持するorg.jivesoftware.smack.RosterGroupオブジェクトが格納されたCollectionを返す。

RosterGroupに対しては、getNema()メソッドを使えばグループ名がわかる。また、getgetEntries()メソッドによってそのグループに所属する仲間のRosterEntryが格納されたCollectionを取得することができる。あとは先ほどの同様にRosterEntryから仲間の情報を取り出せばよい。次のコードのprintRosterWithGroup()は、グループ別に仲間の情報を表示するメソッドの例である。

リスト5

/* グループ別の仲間リストを表示する */
public void printRosterWithGroup() {
    // Rosterオブジェクトを取得
    Roster roster = connection.getRoster();

    // Rosterからグループのリストを取得
    Collection<RosterGroup> groups = roster.getGroups();
    // グループごとにグループ名と仲間の情報を表示
    for (RosterGroup group: groups) {
    System.out.println(group.getName() + ":");
    Collection<RosterEntry> entries = group.getEntries();
    for (RosterEntry entry : entries) {
        System.out.println("    " + entry);
    }
    }
}

このメソッドによる出力は次のようになる。

プロンプト2

友人:
    次郎@google: xxxxxxxx@gmail.com [友人]
仲間:
    三郎: xxxxxxxx@gmail.com [仲間]
マイコミ:
    太郎: xxxxxxxx@gmail.com [マイコミ]

今回はRosterオブジェクトからgetEntries()やgetGroupes()でエントリーやグループを一括で取り出す方法を紹介したが、Rosterクラスにはその他にもユーザIDやグループ名を指定して、特定の仲間、グループのオブジェクトのみを取得するメソッドが用意されている。前回のようにチャットを行う場合でも、本来であれば先にオンラインの仲間のリストを取得しておく必要がある。Smackを使う上ではRosterやPresenceは必須のクラスである。