7. jQueryと組み合わせる
WebSocketのJavaScript APIは極めてシンプルに設計されているので、サードパーティ製のJavaScriptフレームワークとも簡単に組み合わせて利用することができる。本稿では、先ほど作成したチャットアプリケーションのクライアント側のコードを、「jQuery」および「jQuery UI」を組み合わせて使うように書き直した例を、添付サンプルコードの「chat_jquery.html」として用意した。jQueryはjquery.comから、jQuery UIはjqueryui.comから、それぞれ最新版をダウンロードできる。
基本的にはオブジェクト操作やイベントハンドリングの部分をjQueryを利用する形式に置き換えればよく、WebSocketを使うために特別なことをする必要はない。添付した例では、コードを修正するついでに、接続/切断の状態に応じてボタンやテキストフィールドの活性/非活性を切り替える処理を追加している。また、jQuery UIに用意されたテーマ機能を使っているので、図7.1のように見た目も少しだけ修飾されている。
jQueryでWebSocketの利用を少しだけ便利にする「jquery-websocket」のようなプラグインもある。これは、サーバーにメッセージを送る際に自分でJSONオブジェクトを構築する手間を省いてくれるもの。send()メソッドには、次のように第1引数にメッセージのタイプを、第2引数に送りたいデータオブジェクトを渡す。
var webSocket = $.websocket("ws://127.0.0.1:8080/", ...); webSocket.send( 'message', { name: '名前', text: 'テキスト' } );
すると、jquery-websocketは次のようなJSONデータを作成してサーバーに送信する。
{ type: 'message', data: { name: '名前', text: 'テキスト' } );
もっとも、READMEにもある通りjquery-websocketの開発はアクティブではない。そのため、そのままの形で実務に利用するのはお勧めしないが、ほんの数十行の簡単なJavaScriptコードで作られているため、自前でjQuery用のWebSocketプラグインを作る際には参考になるだろう。
本稿のサンプルコードには、先ほどのチャットアプリケーションをjquery-websocketを使うように書き直した例を「chat_jquery_websocket.html」として添付した。
8. ドラッグ可能なオブジェクト情報の送受信
最後に、もう少しリアルタイム性の高い通信を行うサンプルを紹介しよう。チャットアプリケーションと同様にメッセージを複数のクライアントに送信するというものだが、投稿したメッセージは図8.1のように中央の領域に四角いボックスで表示される。自分で投稿したメッセージと他人が投稿したメッセージはボックスの色で区別できる。このボックスはマウスでドラッグして移動することができる。誰かが自分のクライアント内でボックスを移動すると、図8.2のように他のクライアントに表示されているボックスも追随して同じように移動する。
ドラッグ可能なメッセージボックスはjQuery UIのDraggableオブジェクトを利用して実装している。次のように入力したメッセージを表示するdiv要素に対してdraggable()メソッドを呼び出すだけで、ドラッグによる移動が可能になる。ここではcontainment属性でドラッグ可能な範囲を指定している。
var box = $("<div class='box ui-widget-content'>").text(text); box.draggable({ containment: "[data-name='draggable-area']" })
メッセージボックスの情報は、次のようなJSON形式にしてサーバー/クライアント間で共有する(なお、この例ではjquery-websocketは使用していない)。
{ type: 'box', data: { boxid: <識別子>, top: <y座標>, left: <x座標>, text: <メッセージ>, owner: <作成元のセッションID> } }
例えば、ボックスがドラッグされた場合には、次のようにしてJSON化した情報を送信すればよい。
function msgbox_dragged(event, ui) { if (webSocket != null && webSocket.readyState == webSocket.OPEN) { var object = { type: "box", data: { boxid: event.target.id, top: ui.offset.top.toFixed(0) - baseX, left: ui.offset.left.toFixed(0) - baseY, text: $('#'+event.target.id).text(), owner: $('#'+event.target.id).data("owner") } }; var msg = window.JSON.stringify(object); webSocket.send(msg); } }
サーバーからのメッセージを受信した際には、IDを元にして該当するボックスを特定し、それを同じ場所に移動する。
webSocket.onmessage = function(event) { var message = event.data; var json = window.JSON.parse(message); if (json.type == "box") { var boxdata = json.data; var element = document.getElementById(boxdata.boxid); if(element!=null) { // すでに同じIDのボックスがある場合はそれを移動する $("#" + boxdata.boxid).offset({ "top": baseX + boxdata.top, "left": baseY + boxdata.left }); } else { // 無い場合は新規で作成する makeBox(boxdata.boxid, boxdata.top, boxdata.left, boxdata.text, boxdata.owner); } } }
サーバー側のエンドポイントは、送られてきたメッセージボックスの情報をそのまま接続中のすべてのクライアントに転送するような実装になる。
このサンプルの実装例を、クライアント側を「messageboard.html」、サーバー側を「MessageBoardEndpoint.java」としてサンプルコードに添付したので、詳細はそちらを参照していただきたい。
9. まとめ
今回はLibertyプロファイルおよびLiberty Coreで新たに正式サポートされたWebSocketを使って、サーバー/クライアント間でリアルタイム通信を行うWebアプリケーションを作ってみた。WebSocketはプロトコルレベルでHTTPとは異なるため通信を確立するための内部的な処理は複雑だが、プログラム側からこれを利用するためのAPIは極めてシンプルに設計されており、内部の複雑さをまったく意識することなく使用することができる。
WebSocketが登場した初期の段階では、サーバー環境を構築するための選択肢が限られているという問題があったが、現在は各種サーバー製品によるサポートも進んできている。WASもいち早くWebSocketに対応したJavaアプリケーションサーバーの一つである。このように少しずつWebSocketを使う環境が整っていく中で、将来的にこの新しい技術を商用分野でも活用していきたいと考えたならば、重要となるのはやはりエンタープライズレベルのニーズに耐えられるインフラをいかにして構築するかという点だ。
Liberty Coreを利用する場合、今回紹介したようにサーバー側の特別な設定はほとんど必要とせずにWebSocektにも対応できる。Javaで完結したアプリケーションだけでなく、JavaScriptや他の言語によるクライアントの実装とも高い親和性を持っている。そしてエンタープライズ規模への適性についてもWASの実績に裏付けされたものがある。この実績は、将来的なスケールアップを考えたときにTomcatをはじめとするオープンソース系のアプリケーションサーバにはない安心感をもたらしてくれるものだ。Libertyプロファイルの手軽さにWASの信頼性・安定性をプラスしたLiberty Coreは、リアルタイムWebという新しい潮流を商用サービスに導入していく上で極めて有力な選択肢ということができるだろう。