講師 「『公』~これはなんと読むでしょうか?」
学生 「ハム」
講師 「違います」
infoScoop OSSがバージョン3.1になり、いくつかのOpenSocial仕様を実装いたしました。
その中でも今回はガジェット間連携を司るOpenAjax Hubに関して触れてみたいと思います。
OpenAjax HubはOpenSocial自体の仕様とは別にOpenAjax Hubとしての仕様を持っています。
以前まで仕様に存在していたPubSubと同じようなことを実現することができます。
(もちろんその他にも若干のエンハンスメントは存在しています)
フロントエンドにてガジェットが取得したデータをやり取りするためには欠かせない技術の一つです。

OpenAjax Hubでは、ホスト側にManagedHubを生成し、それと同時にハブを利用するガジェット側にコンテナを用意します。
このコンテナはManagedHubに接続する機能を提供するHubClientをガジェット側に提供します。
ガジェット側のコンテナとホスト側のManagedHubが接続することで異なるガジェットにメッセージを送信したり、メッセージの購読を行ったりする仕組みです。
ガジェット側ではHubClientより提供されるpublish()やsubscribe()を実行することで、メッセージの送信や購読を操作します。
ManagedHubへの接続はガジェットインスタンスが生成された時点で非同期に行われます。
メッセージは送信するたびにメッセージの内容とトピックをManagedHubに送付します。
トピックとはメッセージをグループ化するためのキーで、このキーを設定している購読側に送り届けられます。
ですので、購読側はsubscribe()時にトピックを指定することになります。
実際にサンプルガジェットとして下記のようなものを用意してみました。
// publish.xml
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Publish" scrolling="true" height="350">
<Require feature="pubsub-2"/>
</ModulePrefs>
<Content type="html"><![CDATA[
<form>
<input id="topic" value="hogehoge"/><br>
<input id="message" value="message"/>
<input type="button" value="publish" onclick="publish( topic.value,message.value )"/>
</form>
<div id="console"/>
<script type="text/javascript">
gadgets.util;
var c = document.getElementById("console");
function nl() {
c.appendChild( document.createElement("div"));
return {
print: print
};
}
function print( text ) {
c.lastChild.appendChild( document.createTextNode( text ));
}
function main() {
nl().print( window.name || window.id );
}
var n = 0;
var subId;
function publish( topic,message ) {
nl().print([n++, "-", "Topic", topic, "でメッセージ", message, "を送信"].join(" "));
gadgets.Hub.publish( topic,message );
}
main();
</script>
]]></Content>
</Module>
// subscribe.xml
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Subscribe" scrolling="true" height="350">
<Require feature="pubsub-2"/>
</ModulePrefs>
<Content type="html"><![CDATA[
<form>
<input id="topic" value="hogehoge"/>
</form>
<div id="console"/>
<script type="text/javascript">
gadgets.util;
var c = document.getElementById("console");
function nl() {
c.appendChild( document.createElement("div"));
return {
print: print
};
}
function print( text ) {
c.lastChild.appendChild( document.createTextNode( text ));
}
function main() {
nl().print( window.name || window.id );
}
var n = 0;
var subId;
function subscribe( topic ) {
_gel("subId").value = gadgets.Hub.subscribe( topic,function( topic, message, subscriberData ) {
nl().print([n++,"-","Topic", topic, "からのメッセージ", message, "を受信", "(subscriberData=" + subscriberData + ")"].join(" "));
}, this, function(subID){
_gel("subId").value = subID
},"true" );
nl().print([n++,"-","Topic", topic, "を購読", "(subId=" + _gel("subId").value + ")"].join(" "));
}
main();
gadgets.util.registerOnLoadHandler(function(){
subscribe(_gel("topic").value);
});
</script>
]]></Content>
</Module>
publish.xmlで送信したメッセージを、subscribe.xmlにて受け取り、メッセージを表示させる簡単なガジェットです。
subscribe.xmlではonload時に動的に購読するように設定しています。
動かしてみます。

あれ?
動かない。
javascriptデバックツールのfirebugを起動して、リロードしてみます。

OpenAjax.hub.error.disconnect なるエラーが発生しているようです。
最初に記述したようにOpenAjax Hubでは、コンテナの生成とManagedHubへの接続を行ったのちにメッセージの送信や購読を行えるようになります。
つまり、今回の事態はsubscribe.xmlにて動的に購読命令を出した時には、まだManagedHubに接続されていないために発生していたものと言うことになります。
ですので、少し修正してみます。
// subscribe.xml(修正版)
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="Subscribe" scrolling="true" height="350">
<Require feature="pubsub-2"/>
</ModulePrefs>
<Content type="html"><![CDATA[
<form>
<input id="topic" value="hogehoge"/>
</form>
<div id="console"/>
<script type="text/javascript">
gadgets.util;
var c = document.getElementById("console");
function nl() {
c.appendChild( document.createElement("div"));
return {
print: print
};
}
function print( text ) {
c.lastChild.appendChild( document.createTextNode( text ));
}
function main() {
nl().print( window.name || window.id );
}
var n = 0;
var subId;
function subscribe( topic ) {
_gel("subId").value = gadgets.Hub.subscribe( topic,function( topic, message, subscriberData ) {
nl().print([n++,"-","Topic", topic, "からのメッセージ", message, "を受信", "(subscriberData=" + subscriberData + ")"].join(" "));
}, this, function(subID){
_gel("subId").value = subID
},"true" );
nl().print([n++,"-","Topic", topic, "を購読", "(subId=" + _gel("subId").value + ")"].join(" "));
}
main();
//追加したところ
gadgets.HubSettings.onConnect=function(){
gadgets.Hub.subscribe(_gel("topic").value);
}
/* 削除する
gadgets.util.registerOnLoadHandler(function(){
subscribe(_gel("topic").value);
});
*/
</script>
]]></Content>
</Module>
修正版では、registerOnLoadHandler()内でsubscribe()せずに、gadgets.HubSettings.onConnectにsubscribe()する関数を渡しています。
このonConnectは接続が完了した時に実行される処理になります。
接続が非同期に行われる(正確には、ガジェットインスタンスが生成しきった後に非同期に行われる)ため、その終了を待つ必要がある処理を書くために存在しています。
修正したガジェットを使って実験した結果は以下になります。

参考URL
opensocial spec
OpenAjax Hub 2.0 Specification
Firebug