メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2009年7月28日火曜日

[Apache Shindig][お勉強][OpenSocial] メモ95 opensocial.requestSendMessageのサーバ側実装をしてみる(1)

opensocial.requestSendMessageの実装をしてみる。

とりあえず、JavaScript。
方針
ざっと実装方針。
GadgetXML内でrequestSendMessageがコールされると、
ダイアログが出て、送信していいか確認する。
確認後、message.postmessages.createを発行する。
ってな感じ。
ダイアログはYUIをしてみる。

ガジェットXML
ガジェットXMLはこんな感じ。

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <Module>  
  3.   <ModulePrefs title="opensocial.Message">  
  4.     <Require feature="opensocial-0.8" />  
  5.   </ModulePrefs>  
  6.   <Content type="html" view="home,profile,canvas">  
  7.     <![CDATA[  
  8.     <script type="text/javascript">  
  9.       function sendMessage() {  
  10.         var opt_params = [];  
  11.         opt_params[opensocial.Message.Field.TITLE] = 'タイトルだよーん';  
  12.         opt_params[opensocial.Message.Field.TYPE] = opensocial.Message.Type.PRIVATE_MESSAGE;  
  13.         var body = 'テストメッセージだよーん';  
  14.         var msg = opensocial.newMessage(body, opt_params);  
  15.         opensocial.requestSendMessage(opensocial.IdSpec.PersonId.OWNER, msg, call_back);  
  16.       }  
  17.   
  18.       function call_back(status) {  
  19.         if (status.hadError()) {  
  20.           document.getElementById('result').innerHTML = '失敗したよ:' + status.getErrorCode();  
  21.         } else {  
  22.           document.getElementById('result').innerHTML = '送ったよ';  
  23.         }  
  24.       }  
  25.   
  26.     </script>  
  27.     <div id="result"></div>  
  28.     <input type="button" value="メッセージ送信" onclick="sendMessage();" />  
  29.   
  30.     ]]>  
  31.   </Content>  
  32. </Module>  

TITLEとBODYをセットしてrequestSendMessageをコールするだけ。

サーバ側ContainerのJavaScript
さて、1.1-SNAPSHOTのデフォルトだとrequestSendMessageは、NOTIMPLEMENTを返すだけ
なんだけど、どうも動作しない。
動作しないものはほっといて、jsonrpccontainer.jsなどをいじくってみる。
以下いじった結果。


GadgetからrequestSendMessageがコールされると、jsonrpccontainer.jsの
requestSendMessageが呼ばれるようにする。
Gadgetはiframeの中にいて、jsonrpccontainer.jsも同じiframeの中にいる。
jsonrpccontainer.jsのrequestSendMessageは、ダイアログを出すために、
iframeの親のrequestSendMessageをコールする。ここでgadgets.rpcを使用する。
親のrequestSendMessageではYUIのダイアログを表示後、OKを押下されたなら、
今度はiframeの方のrequestSendMessageCallback_関数をコールする。
ここでもgadgets.rpcを使用。

ということで、まずjsonrpccontainer.jsのrequestSendMessage。
  1. JsonRpcContainer.prototype.requestSendMessage = function(recipientIds, message, opt_callback, opt_params) {  
  2.   opt_callback = opt_callback || function(){};  
  3.   opt_params = opt_params || {}; /* 使わないよ */  
  4.   
  5.   var body = gadgets.util.unescapeString(message.getField(  
  6.       opensocial.Message.Field.BODY));  
  7.   var title = gadgets.util.unescapeString(message.getField(  
  8.       opensocial.Message.Field.TITLE));  
  9.   
  10.   if (!body || body.length === 0) {  
  11.     var bodyMsgKey = gadgets.util.unescapeString(message.getField(  
  12.       opensocial.Message.Field.BODY_ID));  
  13.     body = gadgets.Prefs.getMsg(bodyMsgKey);  
  14.   }  
  15.   if (!title || title.length === 0) {  
  16.     var titleMsgKey = gadgets.util.unescapeString(message.getField(  
  17.       opensocial.Message.Field.TITLE_ID));  
  18.     title = gadgets.Prefs.getMsg(titleMsgKey);  
  19.   }  
  20.   var self = this;  
  21.   var callback = function() {  
  22.     var req = opensocial.newDataRequest();  
  23.     var viewer = new opensocial.IdSpec({'userId' : 'VIEWER'});  
  24.     var rpc = { method : "messages.create" };  
  25.     rpc.params = self.translateIdSpec(viewer);  
  26.     rpc.params.appId = "@app";  
  27.   
  28.     FieldTranslations.translateNetworkDistance(viewer, rpc.params);  
  29.   
  30.     /* ここから、とりあえず版。後でちゃんとする */  
  31.     rpc.params.message = {};  
  32.     rpc.params.message["title"] = title;  
  33.     rpc.params.message["body"] = body;  
  34.     rpc.params.message["recipients"] = self.translateIdSpec(self.makeIdSpec(recipientIds))["userId"];  
  35.     /* ここまで、とりあえず版。後でちゃんとする */  
  36.   
  37.     var messageRequest = new JsonRpcRequestItem(rpc);  
  38.   
  39.     req.add(messageRequest, 'key');  
  40.     req.send(function(response) {  
  41.        opt_callback(response.get('key'));  
  42.     });  
  43.   };  
  44.   
  45.   var callbackId = "cId_" + Math.random();  
  46.   callbackIdStore[callbackId] = callback;  
  47.   gadgets.rpc.call(null'requestSendMessage',  
  48.       null,  
  49.       callbackId,  
  50.       recipientIds,  
  51.       title,  
  52.       body);  
  53. };  

callbackIdStoreにcallbackを入れておきたいので、
callbackIdStoreが定義されている、
  1. (function() {  
  2. })();  

の中に定義。
実際にサーバにデータを送信するコードをコールバックとして生成し、
gadgets.rpc.callを読んで親の'requestSendMessage'をコールする。
ちなみに、gadgets.rpc.callの第一引数がnullになっているが、
これは(というか'..'というかルートというか)
という意味。

で、クロスドメイン間通信で親'requestSendMessage'がコールされると。
で以下親の方のrequestSendMessage。
  1. gadgets.IfrGadgetService.prototype.requestSendMessage = function(rpc, callbackId, recipients, title, body) {  
  2.     if (gadgets.container.gadgetService.sendMessageDialog_) {  
  3.       /* 以下YUI前提 */  
  4.       var onSubmit = function() {  
  5.         if (callbackId) {  
  6.           window.setTimeout(function() {  
  7.             gadgets.rpc.call(rpc.f, 'requestSendMessage_callback'null, callbackId, recipients, title, body);  
  8.           }, 0);  
  9.         }  
  10.         this.cancel();  
  11.       };  
  12.       var onCancel = function() {  
  13.         this.cancel();  
  14.       };  
  15.       gadgets.container.gadgetService.sendMessageDialog_.cfg.queueProperty("buttons", [  
  16.         {text: "OK", handler: onSubmit, isDefault: true},  
  17.         {text: "キャンセル", handler: onCancel}  
  18.       ]);  
  19.       document.getElementById('sendMessageDialog_title').innerHTML = title;  
  20.       document.getElementById('sendMessageDialog_body').innerHTML = body;  
  21.       gadgets.container.gadgetService.sendMessageDialog_.render();  
  22.       gadgets.container.gadgetService.sendMessageDialog_.show();  
  23.     }  
  24.     else {  
  25.          if (callbackId) {  
  26.           window.setTimeout(function() {  
  27.             gadgets.rpc.call(rpc.f, 'requestSendMessage_callback'null, callbackId, recipients, title, body);  
  28.           }, 0);  
  29.         }  
  30.   
  31.     }  
  32. };  

な感じ。
多分これじゃだめで、jsonrpccontainer.jsのrequestSendMessageをコールした際に
積み上げたcallbackIdStoreをクリアさせなきゃいけない。
とりあえず、おいといて、
gadgets.container.gadgetService.sendMessageDialog_
というのはYUIのダイアログ。
"OK"ボタンが押下されると、
  1. gadgets.rpc.call(rpc.f, 'requestSendMessage_callback'null, callbackId, recipients, title, body);  

がコール。
gadgets.rpc.callの第一引数にrpc.fが指定されているが、これは
呼び出し元のwindow.nameが入っている。
意味的には、gadgetの'requestSendMessage_callback'をコールせよ、といった感じか。

gadgets.IfrGadgetService.prototype.requestSendMessage
のパラメータはGadget内でのgadgets.rpc.call時と違うんだけど、これは
  1. gadgets.rpc.register('requestSendMessage'function(callbackId, recipients, title, body) {  
  2.   self.requestSendMessage.apply(self, [this, callbackId, recipients, title, body]);  
  3. });  

と定義したから。
第一引数に呼び出し元を判断するために、rpcがわたるようになっている。

でrequestSendMessage_callbackは、、

JsonRpcContainer.requestSendMessageCallback_ = function(callbackId, recipients, title, body) {
var callback = callbackIdStore[callbackId];
if (callback) {
callbackIdStore[callbackId] = null;
callback();
}
};


こんだけ。で完了。

で実行してみると、サーバ側にリクエストが飛ぶ。
今はまだサーバ側の実装はしていないので、

org.apache.shindig.protocol.ProtocolException: The method message.post is not implemented
at jp.qsdn.gms.social.protocol.SpringHandlerRegistry.getRpcHandler(SpringHandlerRegistry.java:137)


ってなExceptionが出ている。
message.postというものは0.8.1には無い??っぽいので、
message.postというものをハンドラから実装してみる。

messages.createが正解。ハンドらから実装する必要なかった。。


ちなみに、
"message.post"という文字列などは、
http://www.mail-archive.com/shindig-dev@incubator.apache.org/msg08286.html
を参考にした。


--
間違えた。
message.postじゃなくて、messages.post。
ちゃんと0.8.1で動くっぽい。
0.8.1じゃなく、Apache Shindig-1.0とのこと。
OpenSocialの仕様にはsendしかないらしい。

--
さらに間違えた。
messages.postじゃなくて、messages.create。
.

0 コメント: