2011年3月24日

Apache Shindig / Java を使ってみる

Apache Shindig を使えるようにしてみます。 Shindig に関しては Web サイトのトップページに簡単な説明があります。

Apache Shindig is an OpenSocial container and helps you to start hosting OpenSocial apps quickly by providing the code to render gadgets, proxy requests, and handle REST and RPC requests.

Apache Shindig's goal is to allow new sites to start hosting social apps in under an hour's worth of work.

Shindig がガジェットの表示、リクエストのプロキシ、REST と RPC リクエストの処理を担当してくれますので、 その仕様に従えばアプリケーションを素早く提供できますよ、という感じでしょうか。 ここでの「仕様」が OpenSocial と呼ばれるもので、 Google や mixi で使われている OpenSocial のコンテナが Apache Shindig だそうです。 同じ仕様のコンテナを提供することで、Google 用に作ったガジェットを mixi でも使えますし、その逆もまた然りとなります。

Shindig に関する説明は各所にありますが、2010年の10月にバージョン 2.0 がリリースされました。 メジャーバージョンアップですので、インストールするときの違いもあるでしょう。 ということで、いくつかの記事を参考にさせて頂きながら、自分でも動作させてみます。

Shindig 自体は2007年12月頃から ASF の Incubator 下で活動が開始され、2009年1月にトップレベルのプロジェクトになりました。

ローカルのマシンで動かしても構いませんが、クリーンな環境の方が失敗する要素が少ないと思いますので、Amazon EC2 を使います。 東京リージョンが追加されていますので、接続速度にこだわる場合には選択肢のひとつとして有望です。 まぁ、輪番停電が実施されている中で東京のデータセンターを選択する必要があるとは思えませんが。。

EC2 インスタンスに接続する

少し前に EC2 で Apache HTTP と Solr を使えるようにしました (Amazon EC2 を使ってみる)。 インスタンスの起動、接続方法はだいたい一緒で、標準の AMI を使います。

ファイアーウォールの設定では 20 番ポート (SSH) と 80 番ポート (HTTP) を開放しておきます。 アプリケーションサーバの動作確認用に 8080 番ポートなどを確認しても構いませんが、 ちょっと確認するだけであれば SSH トンネリングを利用すれば良いと思います。

.ssh/configHostec2shindig にしておきます。

接続例

$ ssh -L8080:localhost:8080 ec2shindig

なお、インスタンスの扱いには Amazon EC2 API Tools が便利そうです。 時間があれば設定しておきたいところです。

SSH で接続したら、Apache と Tomcat をインストールしておきます。

$ sudo yum -y install httpd tomcat6
$ sudo chkconfig httpd on
$ sudo chkconfig tomcat6 on

次に、Apache へのリクエストを Tomcat にプロキシさせるように設定し、サーバを起動しておきます。

$ cat <<'EOF' |sudo tee -a /etc/httpd/conf.d/proxy.conf
ProxyPass / http://{YOUR-INSTANCE-PUBLIC-DNS}:8080/
EOF
$ sudo service httpd start

Shindig の .war アーカイブを配置する

Apache Shindig の サイト からアーカイブをダウンロードします。 Java の実装と PHP の実装がありますが、単に配置するだけならば Java の .war アーカイブを使う方法が簡単に思えましたので、Java 版を使います。 shindig-server-2.0.0.war は予め取得しておきます。

$ sudo mv shindig-server-2.0.0.war /usr/share/tomcat6/webapps/ROOT.war
$ sudo chown tomcat /usr/share/tomcat6/webapps/ROOT.war

.war ファイルを展開し、 web.xml を編集します。 ついでに、Tomcat が 8080 番ポートで動作することを確認しておきます。

$ sudo service tomcat6 start
$ wget -SO /dev/null "http://localhost:8080/"
$ sudo service tomcat6 stop
$ sudo vim /usr/share/tomcat6/webapps/ROOT/WEB-INF/web.xml    --- (*)
$ sudo service tomcat6 start
(*) Shindig のホスト名とポート番号を設定します。
デフォルトではホスト名が localhost 、ポート番号が 8080 番になっています。 下記の NOTE 1 にあるように shindig.hostshindig.port を設定します。 Tomcat の起動設定 (/etc/tomcat6/tomcat6.conf など) でもシステムプロパティとして制御できるはずです。

これで EC2 インスタンスの Public DNS にアクセスすると、次の画面が表示されます。

http://{YOUR-INSTANCE-PUBLIC-DNS}/gadgets/ifr?url=http://miyakemusi.googlecode.com/svn/trunk/tv_gadget/tv.xml

設定に関して注意すべきことが2点挙げられます。

  • Tomcat の ROOT コンテキストで動かす。
  • Apache からプロキシするときに ROOT コンテキストが保持されるようにする。

いずれもリソースの URL 解決という意味で根っこは同じです。 OpenSocial ではクロスドメイン通信を回避するために、コンテナが HTTP リクエストをバイパスさせます。 このときに、コンテンツの URL とプロキシ用の URL を解決しなければなりませんが、 これが Java から JavaScript に変換されています。 ガジェットをうまく表示できない場合は、取得したページのソースを表示してみると問題解決の端緒となるかもしれません。 localhost の記述が存在する場合には shindig.host の設定間違いかもしれませんので、 web.xm を見直します。

ROOT コンテキスト以外で動作させようとするとパスの整合性が崩れてしまいますので、うまく動きません。 たとえば、 .war ファイルの名前を変更せずに webapps ディレクトリに配置すると、 アプリケーションにアクセスする場合には /shindig-server-2.0.0 というパスが必要になります。 一番最初のリクエストはそれで成功しますが、その後に JavaScript を取得する部分に /shindig-server-2.0.0 が渡っていないため、ガジェットを表示できません。

さらに、Apache のプロキシでこのエンドポイントを自由に変更できます。 たとえば proxy.conf に次の定義を入れると、外部からは http://{YOUR-INSTANCE-PUBLIC-DNS}/shindig でアクセスできますが、 JavaScript の通信がうまくいかずにガジェットを表示できません。

ProxyPass /shindig http://{YOUR-INSTANCE-PUBLIC-DNS}:8080/shindig-server-2.0.0

いずれの問題も将来的な実装の変更、あるいはちょっと複雑な Shindig の設定で制御できるのかもしれませんが、 ちょっと始めてみるには遠回りすぎる気がしました。 ROOT/WEB-INF/classes/containers/default/container.js が関係していると思いますが、 とりあえずは ROOT コンテキストで動かしてみることが間違いが少ないはずで、 もっと突っ込んだことを実現する場合にはソースコードを取得して mvn を使って自前でビルドした方が良さそうです。

また、Apache をフロントに置く必然性もありませんので、Tomcat を 80 番ポートで動かすか、 ファイアーウォールで 8080 番ポートを許可すれば良いのかもしれません。 ここでは、EC2 のセキュリティポリシーを使いまわすために上記のようにしています。

NOTE 1: web.xml における shindig.hostshindig-port の設定例です。

<context-param>
    <param-name>system.properties</param-name>
    <param-value>
        shindig.host={YOUR-INSTANCE-PUBLIC-DNS}
        aKey=/shindig/gadgets/proxy?container=default&amp;url=
        shindig.port=80
    </param-value>
</context-param>

NOTE 2: PHP 版は mod_php を使って構築します。
標準の AMI には PHP はインストールされていませんが、 yum でインストールできます。 他のモジュール (curl の PHP 拡張など) に関してもきっとインストールできるでしょう。 パスの問題に関しては分かりません。

ガジェットを追加する

OpenSocial の仕様に基づいた XML を用意し、Web サーバにアップロードします。 例えば、震災発生日からの経過日数を表示するガジェットは次のようになります。

show-elapsed-days-from-east-japan-earthquake.xml

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Pray for Japan!">
    <Require feature="opensocial-0.8" />
  </ModulePrefs>
  <Content type="html">
  <![CDATA[
    <script>
    function showElapsedDays() {
        var earthquake = new Date(2011, 2, 11),
            today = new Date(),
            diff = (today - earthquake) / 86400000;
        document.getElementById('elapsedDays').innerHTML = Math.floor(diff);
    }
    gadgets.util.registerOnLoadHandler(showElapsedDays);
    </script>
    <p>
    今日は東日本大震災から<span id="elapsedDays"></span>日目です。<br />
    1日も早い復興に向けて頑張りましょう!
    </p>
  ]]>
  </Content>
</Module>

XML とその中身の JavaScript のインデントの数に悩みますが、 XML は構造が分かるようにインデント2、JavaScript は XML とは異なることを明示するためにもインデント4にしてあります。

「Web サーバを持っていない!」という場合には Dropbox の Public フォルダを利用できます。 たとえば、上記の XML は http://dl.dropbox.com/u/1880322/os/show-elapsed-days-from-east-japan-earthquake.xml で参照できるようにしてあります。 Shindig の /gadgets/ifr エンドポイントの url パラメータにこの URL を指定することで、ガジェットを表示できます。

終わりに

Apache Shindig をインストールし、簡単なガジェットを追加しました。 ガジェットの仕様は OpenSocial で定義されていますので、仕様に沿っておけば、 コンテナの提供者も利用者も同じものを再利用できます。

仕様がひとつで同じソフトウェアを使うなら、みんなでコンテナを共有すれば良いのでは?という疑問もあるかもしれませんが、 サービスごとにコンテナを提供することにより、サービス固有のユーザー情報を参照できるのは大きなメリットです。 サービスごとにペルソナを使い分けているユーザーには特に顕著な違いとなります。 最近流行の「ソーシャルグラフ」が違うためです。 ただ、実際にサービス提供側がバックエンドのユーザー情報と繋いでいくのは大変かもしれませんが。

既存のサービスにガジェットを追加していく、という観点でも仕様が共有されたコンテナは有効です。 「よそのサービスにあるあの機能が足りない」という場合にも、それぞれが OpenSocial に対応していれば簡単に流用できます。 たとえば、災害後の緊急事態用のガジェットが考えられます。 災害後の非常体制での生活を送る中では「大きなシステム改修/移行に踏み切るほどでもないが、一時的に機能を追加したい」 という要望もあると思います。 OpenSocial でガジェットをプラガブルにしておけば、こうした要望には対応できるのではないでしょうか。 今からでは遅い... かもしれませんが、次に役立てることはできると思います。

ガジェットに関しては、すでに多数の iGoogle ガジェットが開発されていますし、XML で記述されていますから時間をかければ中身を確認できます。 エンタープライズシステムだから、うちは SNS じゃないから、といった認識ではなく、今出来ることを少しでも考えていきたいですね。

コメントを投稿