19 WebLogic ServerでのWebSocketプロトコルの使用方法
この章の内容は次のとおりです。
- WebSocketプロトコルの理解
WebSocketとは、単一のTCP接続を介したクライアントとサーバー間の双方向同時通信を可能にするアプリケーション・プロトコルです。WebSocketプロトコルを使用すると、クライアントとサーバーはそれぞれ独立してデータを送信できます。 - WebLogic ServerのWebSocketの実装の理解
WebLogic ServerのWebSocketの実装では、JSR 356 Java API for Websocketがサポートされます。 - WebSocketアプリケーションの作成の概要
Java API for WebSocket (JSR-356)では、WebアプリケーションにWebSocketエンドポイントを作成、構成およびデプロイできます。また、JSR-356で指定されているWebSocketクライアントAPIを使用すると、任意のJavaアプリケーションからリモートのWebSocketエンドポイントにアクセスできます。 - エンドポイントの作成
コンテナは、デプロイメントURIへの接続ごとに1つのエンドポイント・インスタンスを作成します。インスタンスごとに各接続のユーザーの状態が保持され、開発が簡略化されます。 - WebSocket接続のライフサイクル・イベントの処理
開かれた接続、受信されたメッセージ、エラー、閉じられた接続など、様々なWebSocket接続のライフサイクル・イベントが、アノテーション付きエンドポイントおよびプログラム的なエンドポイントで異なる形式で処理されます。 - WebSocketエンドポイントでのリソースの定義、注入およびアクセス
Java API for WebSocketでは、Contexts and Dependency Injection (CDI)を使用して、WebSocketエンドポイントに必要なリソースを注入したり、リソースにアクセスしたりできます。注入されたリソースは、WebSocket接続のライフサイクル・イベントを処理するメソッド内から使用できます。 - メッセージの送信
Java API for WebSocketでは、テキスト・メッセージ、バイナリ・メッセージおよびpingフレームをエンドポイントからその接続ピアに送信できます。 - WebSocketメッセージのエンコーディングとデコーディング
Java API for WebSocketでは、エンコーダとデコーダを使用して、WebSocketメッセージとカスタムJavaタイプ間での変換をサポートします。このメカニズムでは、オブジェクトのシリアライズとデシリアライズからビジネス・ロジックが切り離されるので、WebSocketアプリケーションがシンプルになります。 - エンドポイント・デプロイメントURIの一部をアプリケーション・パラメータとして指定する方法
ServerEndpoint
アノテーションを使用すると、レベル1のURIテンプレートを使用して、エンドポイント・デプロイメントURIの一部分をアプリケーション・パラメータとして指定できます。URIテンプレートでは、変数拡張を使用してURIの範囲を示します。 - クライアントの状態の管理
コンテナでは、接続ごとにエンドポイント・クラスのインスタンスが作成されるので、クライアントの状態の情報を格納するためのインスタンス変数を定義して使用することができます。 - サーバー・エンドポイントのプログラムによる構成
Java API for WebSocketでは、コンテナでサーバー・エンドポイント・インタフェースを作成する方法を構成できます。 - Java API for WebSocketを使用するアプリケーションの構築
Java API for WebSocketはwlserver/server/lib/api.jar
ファイル内に用意されています。Java API for WebSocketを使用するアプリケーションを構築するには、アプリケーションのコンパイル時にクラスパスにこのライブラリを定義します。 - WebSocketアプリケーションのデプロイ
WebLogic Serverでは、標準のJava EE Webアプリケーション・アーカイブ(WAR)の一部としてWebSocketアプリケーションをデプロイします。これは、スタンドアロンのWebアプリケーションまたはエンタープライズ・アプリケーション内のWARモジュールのいずれかとして行います。 - WebSocketアプリケーションの監視
WebSocketアプリケーションおよびエンドポイントのメッセージ統計およびランタイム・プロパティを監視できます。エンドポイント・レベルでの監視は個々のエンドポイントごとに情報を収集し、一方、アプリケーション・レベルでの監視は指定されたアプリケーションで内デプロイしているすべてのエンドポイントからの情報を集約します。 - プロキシ・サーバーでのWebSocketの使用
WebSocketアプリケーションにアクセスするクライアントは、WebLogic Serverインスタンスに直接接続するか、またはWebSocketプロトコルをサポートするWebプロキシ・サーバーを介して接続する必要があります。 - WebSocketクライアントの記述
通常、WebSocketクライアント・アプリケーションはブラウザ・ベースのクライアントです。Java API for WebSocketは、Java WebSocketクライアントの記述にも使用できます。 - WebSocketアプリケーションの保護
WebLogic Serverでは、Webアプリケーション・アーカイブ(WAR)の一部としてWebSocketアプリケーションをデプロイします。これは、スタンドアロンのWebアプリケーションまたはエンタープライズ・アプリケーション内のWARモジュールのいずれかとして行います。したがって、Webアプリケーションの保護に適用する多くのセキュリティ上の措置を、WebSocketアプリケーションに適用することができます。 - WebSocketメッセージングのプロトコル・フォールバックの有効化
プロトコル・フォールバックは、WebSocketプロトコルがサポートされていない場合に、WebSocketメッセージングの代替転送方法を使用するためのメカニズムを提供します。通常、WebSocketプロトコルがサポートされない理由は、WebSocketオブジェクトが使用できないためか、WebSocketフレームがファイアウォールによってブロックされているためです。このリリースでサポートされている代替転送方法は、HTTPロング・ポーリングのみです。 - 非推奨のAPIからJSR 356 Java API for WebSocketへのアプリケーションの移行
使用中のWebSocketアプリケーションとWebLogic Serverの将来のリリースとの互換性を確保するには、非推奨になったパッケージのかわりにJSR 356 Java API for WebSocketを使用してください。 - WebLogic ServerでのJava API for WebSocketの使用例
ユーザーがクライアントから送信したテキストを、サーバー・エンドポイントでエコーする例について検討します。ユーザーがテキスト・メッセージを送信すると、サーバーはそのメッセージにテキスト(from your server)を追加してユーザーにメッセージを返信します。
WebSocketプロトコルの理解
WebSocketとは、単一のTCP接続を介したクライアントとサーバー間の双方向同時通信を可能にするアプリケーション・プロトコルです。WebSocketプロトコルを使用すると、クライアントとサーバーはそれぞれ独立してデータを送信できます。
HTML5仕様(http://www.w3.org/TR/html5/
)の一部として、WebSocketプロトコルは、ほとんどのブラウザによってサポートされています。WebSocketプロトコルをサポートしているブラウザには、エンドポイントへの接続、メッセージの送信、およびWebSocketイベント(接続を開く、メッセージを受信、接続を閉じるなど)へのコールバック・メソッドの割当てを行うJavaScript APIが搭載されています。
WebSocketプロトコルの全般的な情報については、http://tools.ietf.org/html/rfc6455
を参照してください。
HTTPリクエスト/レスポンス・モデルの限界
HTTPで使用されている従来のリクエスト/レスポンス・モデルでは、クライアントがリソースをリクエストし、サーバーがレスポンスを返します。このやり取りは常にクライアントによって開始されるので、クライアントが先にリクエストを出さなければ、サーバーはデータを送信できません。このモデルは、変更頻度の低いドキュメントをクライアントが時々リクエストするような場合にWorld Wide Webで問題なく機能しましたが、コンテンツの更新が頻繁で、よりインタラクティブなWebエクスペリエンスが求められるようになるにしたがって、このアプローチの限界が次第に明らかになってきました。WebSocketプロトコルは、クライアントとサーバー間に全二重通信チャネルを提供することで、このような限界に取り組みます。WebSocketは、他のクライアント・テクノロジ(JavaScriptやHTML5など)と組み合せて、Webアプリケーションのユーザー・エクスペリエンスをより豊かにすることができます。
親トピック: WebSocketプロトコルの理解
WebSocketエンドポイント
WebSocketアプリケーションでは、サーバーがWebSocketエンドポイントをパブリッシュし、クライアントがそのエンドポイントのURIを使用してサーバーに接続します。
WebSocketエンドポイントは、次に示すいずれかの形式のURIで表現されます。
ws://host:port/path?query wss://host:port/path?query
ws
スキームは、暗号化されていないWebSocket接続を表します。
wss
スキームは、暗号化されたWebSocket接続を表します。
これらの形式の残りの構成要素を次に示します。
- host
-
[RFC3986]の3.2.2項で定義されているホスト。
- port
-
オプション。[RFC3986]の3.2.3項で定義されているポート。デフォルトのポート番号は、80 (非暗号化接続の場合)および443 (暗号化接続の場合)です。
- path
-
[RFC3986]の3.3項で定義されているパス。WebSocketエンドポイントのパスは、サーバー内のエンドポイントの場所を示します。
- query
-
オプション。[RFC3986]の3.4項で定義されている問合せ。
親トピック: WebSocketプロトコルの理解
WebSocketプロトコルのハンドシェイク・リクエスト
WebSocket接続を開始するために、クライアントはサーバーがパブリッシュしたWebSocketエンドポイントにハンドシェイク・リクエストを送信します。クライアントは、エンドポイントのURIを使用してエンドポイントの場所を指定します。ハンドシェイク・リクエストが検証に合格し、サーバーがリクエストを受け入れると、接続が確立されます。ハンドシェイクは既存のHTTPベースのインフラストラクチャと互換性があります。つまり、WebサーバーではハンドシェイクをHTTP接続のアップグレード・リクエストとして解釈します。
例19-1 WebSocketクライアントからのハンドシェイク・リクエスト
次の例は、クライアントからのハンドシェイク・リクエストを示しています。
GET /path/to/websocket/endpoint HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg== Origin: http://localhost Sec-WebSocket-Version: 13
例19-2 WebSocketクライアントからのハンドシェイク・リクエストに対するサーバー・レスポンス
次の例は、クライアントからのハンドシェイク・リクエストに対するサーバーからのハンドシェイク・レスポンスを示しています。
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
サーバーは、認識された操作をSec-WebSocket-Key
ヘッダーの値に適用して、Sec-WebSocket-Accept
ヘッダーの値を生成します。クライアントは、同じ操作をSec-WebSocket-Key
ヘッダーの値に適用します。その結果がサーバーから受信した値と一致する場合、接続が正常に確立されます。ハンドシェイクに成功すると、クライアントとサーバーはメッセージを相互送信できます。
親トピック: WebSocketプロトコルの理解
WebSocketプロトコルのメッセージングとデータ転送
接続が確立されると、WebSocketプロトコルは対称性を示します。つまり、クライアントとWebLogic Serverインスタンスは、接続が開いている間はいつでもメッセージを相互送信可能で、その接続をいつでも閉じることができます。通常、クライアントは1つのサーバーとのみ接続しますが、サーバーは複数のクライアントから接続を受け入れます。
WebSocketは、テキスト・メッセージ(UTF-8でエンコードされたもの)とバイナリ・メッセージをサポートします。WebSocketの制御フレームは、close、pingおよびpong (pingフレームへのレスポンス)です。pingフレームとpongフレームには、アプリケーション・データが含まれている場合もあります。
親トピック: WebSocketプロトコルの理解
WebLogic ServerのWebSocketの実装の理解
WebLogic ServerのWebSocketの実装では、JSR 356 Java API for Websocketがサポートされます。
Java API for WebSocketの詳細は、JSR 356の仕様(http://www.jcp.org/en/jsr/detail?id=356
)を参照してください。
ノート:
リリース12.1.2で導入された固有のWebLogic Server WebSocket APIは非推奨になりましたが、下位互換性のために引き続きサポートされます。
JSR 356 Java API for WebSocketは固有のWebLogic Server WebSocket APIと共存できますが、アプリケーションに両方のAPIに対するコールを含めることはできません。アプリケーションで使用できるのは、一方のAPIのみです。
非推奨になったAPIの使用方法の詳細は、Oracle WebLogic Server 12c (12.1.2)のドキュメント(『Oracle WebLogic Serverアプリケーションの開発12c (12.1.2)』の第17章「WebLogic ServerでのWebSocketの使用」)を参照してください。
WebLogic ServerのWebSocketの実装には、次のコンポーネントが含まれています。
WebSocketプロトコルの実装
WebLogic ServerでのWebSocketプロトコルの実装は、JSR 356 Java API for WebSocketのリファレンス実装によって提供されます。このWebSocketプロトコルの実装では、接続アップグレードの処理、接続の確立と管理およびクライアントとのやり取りの処理を行います。
WebLogic WebSocket Java API
WebLogic WebSocket APIは、JSR 356 Java API for WebSocketのリファレンス実装によって提供されます。このAPIは次パッケージで構成されます。
-
javax.websocket.server
-
このパッケージには、サーバーのエンドポイントを作成および構成するためのアノテーション、クラスおよびインタフェースが含まれています。
-
javax.websocket
-
このパッケージには、クライアントとサーバーのエンドポイントに共通のアノテーション、クラスおよびインタフェースが含まれています。
これらのパッケージのAPIリファレンスに関するドキュメントは、Java EE 8のAPI仕様の次の各項を参照してください。
WebSocketメッセージングのプロトコル・フォールバック
プロトコル・フォールバックは、WebSocketプロトコルがサポートされていない場合に、WebSocketメッセージングの代替転送方法を使用するためのメカニズムを提供します。通常、WebSocketプロトコルがサポートされない理由は、WebSocketオブジェクトが使用できないためか、WebSocketフレームがファイアウォールによってブロックされているためです。このリリースでサポートされている代替転送方法は、HTTPロング・ポーリングのみです。
プロトコル・フォールバックを使用すると、実行時環境でWebSocketプロトコルがサポートされているかどうかにかかわらず、標準のプログラミングAPIを使用してWebSocketメッセージングを実行できます。詳細は、「WebSocketメッセージングのプロトコル・フォールバックの有効化」を参照してください。
WebSocketサンプル・アプリケーション
WebLogic Serverのサンプル・コンポーネントをマシンにインストールして構成すると、WebSocketのサンプルを使用してWebLogic ServerでのWebSocketの使用方法を実際に確認できます。このようなサンプルの実行の詳細は、『Oracle WebLogic Serverの理解』の「サンプル・アプリケーションおよびサンプル・コード」を参照してください。
WebSocketアプリケーションの作成の概要
Java API for WebSocket (JSR-356)では、WebアプリケーションにWebSocketエンドポイントを作成、構成およびデプロイできます。また、JSR-356で指定されているWebSocketクライアントAPIを使用すると、任意のJavaアプリケーションからリモートのWebSocketエンドポイントにアクセスできます。
WebSocketエンドポイントの作成およびデプロイの手順を次に示します。
- エンドポイント・クラスを作成します。
- エンドポイントのライフサイクル・メソッドを実装します。
- エンドポイントにビジネス・ロジックを追加します。
- Webアプリケーション内にエンドポイントをデプロイします。
エンドポイントの作成
コンテナは、デプロイメントURIへの接続ごとに1つのエンドポイント・インスタンスを作成します。インスタンスごとに各接続のユーザーの状態が保持され、開発が簡略化されます。
Java API for WebSocketでは、次の種類のエンドポイントを作成できます。
-
アノテーション付きエンドポイント
-
プログラム的なエンドポイント
プログラム的なエンドポイントとアノテーション付きエンドポイントでは手順が異なります。多くの場合、プログラム的なエンドポイントよりもアノテーション付きエンドポイントの方が簡単に作成およびデプロイできます。
ノート:
サーブレットとは対照的に、WebSocketエンドポイントは複数回インスタンス化されます。コンテナは、デプロイメントURIへの接続ごとに1つのエンドポイント・インスタンスを作成します。各インスタンスは1の接続のみに関連付けられます。この動作では、エンドポイント・インスタンスのコードを実行しているスレッドは常に1つのみなので、接続ごとにユーザーの状態を簡単に維持でき、デプロイメントが簡素化されます。
アノテーション付きエンドポイントの作成
Java API for WebSocketでは、アノテーション付きサーバー・エンドポイントとアノテーション付きクライアント・エンドポイントを作成できます。
アノテーション付きサーバー・エンドポイントを作成するには:
例19-3 アノテーション付きサーバー・エンドポイント・クラスの宣言
次の例は、アノテーション付きサーバー・エンドポイント・クラスの宣言方法を示しています。プログラム的なエンドポイント・クラスを宣言して同じエンドポイントを表す方法の例は、例19-5を参照してください。
この例では、アノテーション付きサーバー・エンドポイント・クラスEchoEndpoint
を宣言します。エンドポイントは、アプリケーションからの相対パス/echoにデプロイされます。
import javax.websocket.server.ServerEndpoint; ... @ServerEndpoint("/echo") public class EchoEndpoint { ... }
例19-4 アノテーション付きクライアント・エンドポイント・クラスの宣言
アノテーション付きクライアント・エンドポイントを作成するには:
-
クライアント・エンドポイントを表すPlain Old Java Object (POJO)クラスを記述します。
このクラスは、引数を取るコンストラクタを持つことができます。ただし、このようなエンドポイントからサーバー・エンドポイントに接続するには、インスタンスを取得するconnectToServerメソッドの変数を使用する必要があります。クラスを取得する変数は使用できません。詳細は、「Java WebSocketクライアントのサーバー・エンドポイントへの接続」を参照してください。
-
avax.websocket.ClientEndpoint
アノテーションでPOJOクラスのクラス宣言にアノテーションを付けます。このアノテーションは、クラスがWebSocketクライアント・エンドポイントを表していることを示します。
次の例は、アノテーション付きクライアント・エンドポイント・クラスの宣言方法を示しています。
この例では、アノテーション付きクライアント・エンドポイント・クラスExampleEndpoint
を宣言します。
import javax.websocket.ClientEndpoint; ... @ClientEndpoint public class ExampleEndpoint { ... }
親トピック: エンドポイントの作成
プログラム的なエンドポイントの作成
プログラム的なエンドポイントを作成するには、エンドポイントのスーパークラスのメソッドをオーバーライドして、WebSocket接続のライフサイクル・イベントを処理する必要があります。詳細は、「プログラム的なWebSocketエンドポイントでのライフサイクル・イベントの処理」を参照してください。プログラム的なエンドポイントは、アプリケーションに自動的にデプロイされません。エンドポイントは明示的にデプロイする必要があります。詳細は、「アプリケーション内でのプログラム的なエンドポイントへのパスの指定」を参照してください。
プログラム的なエンドポイントを作成するには、javax.websocket.Endpoint
クラスを拡張します。
例19-5は、プログラム的なエンドポイント・クラスの宣言方法を示しています。アノテーション付きエンドポイント・クラスを宣言して同じエンドポイントを表す方法の例は、例19-3を参照してください。
例19-5 プログラム的なエンドポイント・クラスの宣言
この例では、プログラム的なエンドポイント・クラスEchoEndpoint
を宣言します。アプリケーション内でこのエンドポイントへのパスを指定する方法を示した例は、例19-6を参照してください。
import javax.websocket.Endpoint; ... public class EchoEndpoint extends Endpoint { ... }
親トピック: エンドポイントの作成
アプリケーション内でのプログラム的なエンドポイントへのパスの指定
リモート・クライアントがプログラム的なエンドポイントに接続できるようにするには、アプリケーション内でエンドポイントへのパスを指定する必要があります。
アプリケーション内でプログラム的なエンドポイントへのパスを指定するには:
アプリケーションをデプロイすると、エンドポイントが次のURIで使用可能になります。
ws://host:port/application/path
このURIの次の項目を置き換えます。
- host
-
アプリケーションが稼働しているホスト。
- port
-
WebLogic Serverのクライアント・リクエストのリスニング・ポート。
- application
-
アプリケーションのデプロイ名。
- path
-
create
メソッドの呼出しで指定したパス。
たとえば、ローカル・ホスト上で稼働している/echoapp
アプリケーションからの相対パス/echo
にあるエンドポイントのURIは、ws://localhost:8890/echoapp/echo
です。
例19-6は、このタスクを1行のJavaコードで実行する方法を示しています。
例19-6 アプリケーション内でのプログラム的なエンドポイントへのパスの指定
この例では、アプリケーション内でのプログラム的なエンドポイントEchoEndpoint
(例19-5で作成)へのパスとして、/echo
を指定します。
import javax.websocket.server.ServerEndpointConfig.Builder; ... ServerEndpointConfig.Builder.create(EchoEndpoint.class, "/echo").build(); ...
親トピック: エンドポイントの作成
WebSocket接続のライフサイクル・イベントの処理
開かれた接続、受信されたメッセージ、エラー、閉じられた接続など、様々なWebSocket接続のライフサイクル・イベントが、アノテーション付きエンドポイントおよびプログラム的なエンドポイントで異なる形式で処理されます。
WebSocket接続のライフサイクル・イベントの処理方法は、接続のエンドポイントがアノテーション付きエンドポイントか、プログラム的なエンドポイントかによって異なります。詳細は、次を参照してください:
アノテーション付きWebSocketエンドポイントでのライフサイクル・イベントの処理
アノテーション付きWebSocketでのライフサイクル・イベントの処理では、次のタスクを実行します。
表19-1は、WebSocketエンドポイントのライフサイクル・イベントと、その処理メソッドを指定するためのアノテーション(javax.websocket
パッケージで利用可能)を示しています。この表には、これらのメソッドで最もよく使用されるパラメータが例示されています。各例では、オプションのjavax.websocket.Session
パラメータが使用されています。Session
オブジェクトは、WebSocketエンドポイントのペア間の対話を表します。
アノテーションで使用可能なパラメータの組合せの詳細は、アノテーションのAPIリファレンスを参照してください。
表19-1 WebSocketエンドポイントのライフサイクル・イベントに使用するjavax.websocketのアノテーション
イベント | アノテーション | 例 |
---|---|---|
Connection opened |
|
|
Message received |
|
|
Error |
|
|
Connection closed |
|
親トピック: WebSocket接続のライフサイクル・イベントの処理
Connection openedイベントの処理
Connection openedイベントを処理して、新しいWebSocketの対話が開始されたことをユーザーに通知します。
Connection openedイベントを処理するには、イベントを処理するメソッドにOnOpen
アノテーションを付けます。
例19-7は、Connection openedイベントの処理方法を示しています。
例19-7 Connection openedイベントの処理
この例では、WebSocket接続が開いたときに、セッションの識別子が出力されます。
import javax.websocket.OnOpen; import javax.websocket.Session; ... @OnOpen public void openedConnection (Session session) { System.out.println("WebSocket opened: " + session.getId()); } ...
Message receivedイベントの処理
-
テキスト・メッセージ
-
バイナリ・メッセージ
-
Pongメッセージ
例19-8 アノテーション付きエンドポイントでの受信テキスト・メッセージの処理
次の例は、アノテーション付きエンドポイントでの受信テキスト・メッセージの処理方法を示しています。
この例では、このエンドポイントのピアにメッセージを返信することで、すべての受信テキスト・メッセージに応答します。OnMessage
アノテーションの付いたメソッドはエンドポイント・クラスのメソッドで、個別のメッセージ・ハンドラ・クラスではありません。
プログラム的なエンドポイントで同じ操作を実行する方法の例は、例19-12を参照してください。
import java.io.IOException; import javax.websocket.OnMessage; import javax.websocket.Session; ... @OnMessage public String onMessage(String msg) throws IOException { return msg; } ...
例19-9 全タイプの受信メッセージの処理方法
この例では、受信したテキスト・メッセージ、バイナリ・メッセージおよびpongメッセージを処理します。テキスト・メッセージは、String
オブジェクトとしてメッセージ全体が受信されます。バイナリ・メッセージは、ByteBuffer
オブジェクトとしてメッセージ全体が受信されます。
import java.nio.ByteBuffer; import javax.websocket.OnMessage; import javax.websocket.PongMessage; import javax.websocket.Session; ... @OnMessage public void textMessage(Session session, String msg) { System.out.println("Text message: " + msg); } @OnMessage public void binaryMessage(Session session, ByteBuffer msg) { System.out.println("Binary message: " + msg.toString()); } @OnMessage public void pongMessage(Session session, PongMessage msg) { System.out.println("Pong message: " + msg.getApplicationData().toString()); } ...
Errorイベントの処理
処理する必要があるErrorイベントは、WebSocketプロトコルでモデル化されていないイベントのみです。たとえば:
-
接続時の問題
-
メッセージ・ハンドラからのランタイム・エラー
-
メッセージ・デコード時の変換エラー
Errorイベントを処理するには、イベント処理のメソッドにOnError
アノテーションを付けます。
例19-10は、Errorイベントの処理方法を示しています。
例19-10 Errorイベントの処理
この例では、Errorイベントに応答して、スタック・トレースを出力します。
import javax.websocket.OnError; import javax.websocket.Session; ... @OnError public void error(Session session, Throwable t) { t.printStackTrace(); ... }
Connection closedイベントの処理
Connection closedイベントを処理する必要があるのは、接続を閉じる前になんらかの特別な処理が必要な場合のみです(たとえば、接続が閉じられた後でデータを使用できなくなる前に、IDなどのセッション属性やセッションが保持している任意のアプリケーション・データを取得する場合など)。
Connection closedイベントを処理するには、イベント処理のメソッドにOnClose
アノテーションを付けます。
例19-11は、Connection closedイベントの処理方法を示しています。
例19-11 Connection closedイベントの処理
この例では、Connection closedイベントに応答して、Someone is disconnecting...
というメッセージを出力します。
import javax.websocket.OnClose; import javax.websocket.Session; ... @OnClose public void bye(Session remote) { System.out.println("Someone is disconnecting..."); } ...
プログラム的なWebSocketエンドポイントでのライフサイクル・イベントの処理
表19-2は、プログラム的なWebSocketエンドポイントでのライフサイクル・イベントの処理方法をまとめたものです。
表19-2 プログラム的なWebSocketエンドポイントでのライフサイクル・イベントの処理
イベント | 処理方法 |
---|---|
Connection opened |
|
Message received |
|
Error |
オプション: このメソッドをオーバーライドしないと、エラー発生時に、エンドポイントが |
Connection closed |
オプション: このメソッドをオーバーライドしないと、接続が閉じられる前に、エンドポイントが |
例19-12は、Connection openedイベントとMessage receivedイベントを処理して、プログラム的なエンドポイントで受信テキスト・メッセージを処理する方法を示しています。
例19-12 プログラム的なエンドポイントでの受信テキスト・メッセージの処理
この例では、すべての受信テキスト・メッセージをエコーします。この例では、Endpoint
クラスのonOpen
メソッド(このクラスで唯一の抽象メソッド)をオーバーライドします。
Session
パラメータは、このエンドポイントとリモートのエンドポイント間の対話を表します。addMessageHandler
メソッドはメッセージ・ハンドラを登録し、getBasicRemote
メソッドはリモート・エンドポイントを表すオブジェクトを返します。
メッセージ・ハンドラは、無名内部クラスとして実装されています。エンドポイントでテキスト・メッセージを受信すると、メッセージ・ハンドラのonMessage
メソッドが呼び出されます。
メッセージの送信の詳細は、「メッセージの送信」を参照してください。
アノテーション付きエンドポイントで同じ操作を実行する方法の例は、例19-8を参照してください。
import java.io.IOException; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.Session; ... @Override public void onOpen(final Session session, EndpointConfig config) { session.addMessageHandler(new MessageHandler.Whole<String>() { @Override public void onMessage(String msg) { try { session.getBasicRemote().sendText(msg); } catch (IOException e) { ... } } }); } ...
親トピック: WebSocket接続のライフサイクル・イベントの処理
WebSocketエンドポイントでのリソースの定義、注入およびアクセス
Java API for WebSocketでは、Contexts and Dependency Injection (CDI)を使用して、WebSocketエンドポイントに必要なリソースを注入したり、リソースにアクセスしたりできます。注入されたリソースは、WebSocket接続のライフサイクル・イベントを処理するメソッド内から使用できます。
CDIの詳細は、Contexts and Dependency Injection for the Java EE platformの使用方法を参照してください。
WebSocketエンドポイントでリソースを定義、注入およびアクセスする手順:
例19-13 WebSocketエンドポイントでのマネージドBeanの定義
この例では、マネージドBeanクラスInjectedSimpleBean
を定義します。
import javax.annotation.PostConstruct; public class InjectedSimpleBean { private static final String TEXT = " (from your server)"; private boolean postConstructCalled = false; public String getText() { return postConstructCalled ? TEXT : null; } @PostConstruct public void postConstruct() { postConstructCalled = true; } }
例19-14 WebSocketエンドポイントでのリソースの注入およびアクセス
この例では、InjectedSimpleBean
マネージドBeanクラスのインスタンスを、サーバー・エンドポイントSimpleEndpoint
に注入します。エンドポイントがメッセージを受信すると、注入されたBean上でgetText
メソッドが呼び出されます。メソッドからテキスト(sent from your server)
が返されます。その後で、元のメッセージと収集されたデータの連結メッセージがエンドポイントから返信されます。
InjectedSimpleBean
マネージドBeanクラスは、例19-13で定義されています。
import javax.websocket.OnMessage; import javax.websocket.server.ServerEndpoint; import javax.annotation.PostConstruct; import javax.inject.Inject; @ServerEndpoint(value = "/simple") public class SimpleEndpoint { private boolean postConstructCalled = false; @Inject InjectedSimpleBean bean; @OnMessage public String echo(String message) { return postConstructCalled ? String.format("%s%s", message, bean.getText()) : "PostConstruct was not called"; } @PostConstruct public void postConstruct() { postConstructCalled = true; } }
メッセージの送信
Java API for WebSocketでは、テキスト・メッセージ、バイナリ・メッセージおよびpingフレームをエンドポイントからその接続ピアに送信できます。
-
テキスト・メッセージ
-
バイナリ・メッセージ
-
Pingフレーム
エンドポイントの単一ピアへのメッセージ送信
エンドポイントの単一ピアにメッセージを送信するには:
例19-15 エンドポイントの単一ピアへのメッセージ送信
この例では、このエンドポイントのピアにメッセージを返信することで、すべての受信テキスト・メッセージに応答します。
import java.io.IOException; import javax.websocket.OnMessage; import javax.websocket.Session; ... @OnMessage public void onMessage(Session session, String msg) { try { session.getBasicRemote().sendText(msg); } catch (IOException e) { ... } } ...
親トピック: メッセージの送信
エンドポイントのすべてのピアへのメッセージ送信
一部のWebSocketアプリケーションでは、アプリケーションのWebSocketエンドポイントのすべての接続ピアに対してメッセージを送信する必要があります。たとえば:
-
株式アプリケーションでは、すべての接続クライアントに株価情報を送信する必要があります。
-
チャット・アプリケーションでは、1人のユーザーからのメッセージを、同じチャット・ルーム内の他のすべてのクライアントに送信する必要があります。
-
オンライン・オークション・アプリケーションでは、アイテムのすべての入札者に最新の付け値を送信する必要があります。
しかし、エンドポイント・クラスの各インスタンスは1つの接続およびピアにのみ関連付けられます。したがって、エンドポイントのすべてのピアにメッセージを送信するには、同じエンドポイントへの接続を表す開いているWebSocketセッションすべてに対して、操作を繰り返す必要があります。
エンドポイントのすべてのピアにメッセージを送信するには:
例19-16 エンドポイントのすべてのピアへのメッセージ送信
この例では、受信テキスト・メッセージをすべての接続ピアに転送します。
import java.io.IOException; import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; ... @ServerEndpoint("/echoall") public static class EchoAllEndpoint { @OnMessage public void messageReceived(Session session, String msg) { for (Session sess : session.getOpenSessions()) { try { sess.getBasicRemote().sendText(msg); } catch (IOException e) { // handle exception } } } }
エンドポイントのすべてのピアにメッセージを送信する場合の効率性の確保
多数のメッセージが送信される実際のアプリケーションでは、複数のスレッドを使用することで、アプリケーションからメッセージを効率的に送信できるようになります。
開いているWebSocket接続が多すぎる場合、1つのスレッドを使用してメッセージをブロードキャストすることは非効率です。なぜなら、繰り返しプロセスにおいては、クライアントがメッセージを受信するのにかかる時間は、その場所に依存するからです。何千ものWebSocket接続が開いていると、繰り返しが遅くなるため、一部のクライアントはメッセージを早く受信するようになりますが、メッセージの受信がかなり後になるクライアントも出てきます。この遅れは、特定の状況では許容できません。たとえば、株式アプリケーションでは、各クライアントができるかぎり早く株価データを受信する必要があります。
効率を上げるために、アプリケーションで、開いているWebSocket接続を複数のグループに分割し、複数のスレッドを使用して、WebSocket接続の各グループにメッセージをブロードキャストすることができます。
親トピック: メッセージの送信
WebSocketエンドポイントのスレッド・セーフティの確保
Java API for WebSocketの仕様では、Java EE実装においてはエンドポイント・クラスを接続ごとに1回ずつインスタンス化することが求められています。この要件によって、WebSocketエンドポイント・クラスのコードを実行しているスレッドは常に1つのみであることが保証されるので、WebSocketエンドポイントのデプロイメントが容易になります。エンドポイントに新規スレッドを導入する場合は、複数のスレッドからアクセスされる変数およびメソッドがスレッド・セーフであることを保証する必要があります。
親トピック: メッセージの送信
WebSocketメッセージのエンコーディングとデコーディング
Java API for WebSocketでは、エンコーダとデコーダを使用して、WebSocketメッセージとカスタムJavaタイプ間での変換をサポートします。このメカニズムでは、オブジェクトのシリアライズとデシリアライズからビジネス・ロジックが切り離されるので、WebSocketアプリケーションがシンプルになります。
エンコーダはJavaオブジェクトを取得して、WebSocketのテキスト・メッセージまたはバイナリ・メッセージとして送信可能な表現を生成します。たとえば、エンコーダは通常、JavaScript Object Notation (JSON)表現、Extensible Markup Language (XML)表現またはバイナリ表現を生成します。デコーダは逆の役割を果します。つまり、WebSocketメッセージを読み取ってJavaオブジェクトを作成します。
ノート:
複数のJavaタイプを同じタイプのWebSocketメッセージとして送受信する必要がある場合は、タイプの定義で共通クラスを拡張します。たとえば、JavaタイプMessageA
およびMessageB
をテキスト・メッセージとして送受信する必要がある場合は、これらのタイプの定義で共通クラスMessage
を拡張します。
このようにタイプを定義することにより、単一のデコーダ・クラスの実装で、複数のタイプに対応できます。
WebSocketメッセージとしてのJavaオブジェクトのエンコーディング
テキスト・メッセージ用エンコーダとバイナリ・メッセージ用エンコーダは、それぞれ複数指定できます。エンドポイントと同様に、エンコーダ・インスタンスは1つのWebSocket接続およびピアにのみ関連付けられます。したがって、エンドポイント・インスタンスのコードを実行しているスレッドは常に1つのみです。
JavaオブジェクトをWebSocketメッセージとしてエンコードするには:
次の例では、Javaタイプcom.example.game.message.MessageA
およびcom.example.game.message.MessageB
をテキスト・メッセージとして送信する方法を示します。
例19-17 エンコーダ・インタフェースの実装
この例では、Encoder.Text<MessageA>
インタフェースを実装します。
package com.example.game.encoder; import javax.websocket.EncodeException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; import com.example.game.message.MessageA; ... public class MessageATextEncoder implements Encoder.Text<MessageA> { @Override public void init(EndpointConfig ec) { } @Override public void destroy() { } @Override public String encode(MessageA msgA) throws EncodeException { // Access msgA's properties and convert to JSON text... return msgAJsonString; } ... }
Encoder.Text<MessageB>
を実装する場合も同様です。
例19-18 アノテーション付きWebSocketエンドポイント用のエンコーダの定義
この例では、エンコーダ・クラスMessageATextEncoder.class
およびMessageBTextEncoder.class
を、WebSocketサーバー・エンドポイントEncEndpoint
に定義します。
package com.example.game; import javax.websocket.server.ServerEndpoint; import com.example.game.encoder.MessageATextEncoder; import com.example.game.encoder.MessageBTextEncoder; ... @ServerEndpoint( value = "/myendpoint", encoders = { MessageATextEncoder.class, MessageBTextEncoder.class } ... ) public class EncEndpoint { ... }
例19-19 WebSocketメッセージとしてエンコードされたJavaオブジェクトの送信
この例では、sendObject
メソッドを使用して、MessageA
オブジェクトおよびMessageB
オブジェクトをWebSocketメッセージとして送信します。
import javax.websocket.Session; ... import com.example.game.message.MessageA; import com.example.game.message.MessageB; ... MessageA msgA = new MessageA(...); MessageB msgB = new MessageB(...); session.getBasicRemote.sendObject(msgA); session.getBasicRemote.sendObject(msgB); ...
JavaオブジェクトとしてのWebSocketメッセージのデコーディング
エンコーダとは異なり、バイナリ・メッセージ用デコーダとテキスト・メッセージ用デコーダは、それぞれ最大で1つしか指定できません。エンドポイントと同様に、デコーダ・インスタンスは1つのWebSocket接続およびピアにのみ関連付けられているので、デコーダ・インスタンスのコードを実行しているスレッドは常に1つのみです。
WebSocketメッセージをJavaオブジェクトとしてデコードするには:
次の例では、WebSocketテキスト・メッセージをJavaタイプcom.example.game.message.MessageA
およびcom.example.game.message.MessageB
としてデコードする方法を示します。
この例では、Javaタイプcom.example.game.message.MessageA
およびcom.example.game.message.MessageB
でcom.example.game.message.Message
クラスが拡張されているものと仮定します。
例19-20 デコーダ・インタフェースの実装
この例では、Decoder.Text<Message>
インタフェースを実装します。
エンドポイントで使用できるテキスト・メッセージ用デコーダは1つのみなので、Message
スーパークラスのデコーダを実装することになります。このデコーダを使用して、Message
のサブクラスをデコードします。
package com.example.game.decoder; import javax.websocket.DecodeException; import javax.websocket.Decoder; import javax.websocket.EndpointConfig; import com.example.game.message.Message; import com.example.game.message.MessageA; import com.example.game.message.MessageB; ... public class MessageTextDecoder implements Decoder.Text<Message> { @Override public void init(EndpointConfig ec) { } @Override public void destroy() { } @Override public Message decode(String string) throws DecodeException { // Read message... if ( /* message is an A message */ ) return new MessageA(...); else if ( /* message is a B message */ ) return new MessageB(...); } @Override public boolean willDecode(String string) { // Determine if the message can be converted into either a // MessageA object or a MessageB object... return canDecode; } }
例19-21 アノテーション付きWebSocketエンドポイント用のデコーダの定義
この例では、デコーダ・クラスMessageTextDecoder.class
を、WebSocketサーバー・エンドポイントEncEndpoint
に定義します。
完全を期すため、この例には、例19-18で示したエンコーダ・クラスMessageATextEncoder.class
およびMessageBTextEncoder.class
の定義も含まれています。
package com.example.game; import javax.websocket.server.ServerEndpoint; import com.example.game.encoder.MessageATextEncoder; import com.example.game.encoder.MessageBTextEncoder; import com.example.game.decoder.MessageTextDecoder; ... @ServerEndpoint( value = "/myendpoint", encoders = { MessageATextEncoder.class, MessageBTextEncoder.class }, decoders = { MessageTextDecoder.class } ) public class EncEndpoint { ... }
例19-22 JavaオブジェクトとしてエンコードされたWebSocketメッセージの受信
この例では、MessageA
オブジェクトおよびMessageB
オブジェクトを受信するmessage
メソッドを定義します。
import javax.websocket.OnMessage; import javax.websocket.Session; ... import com.example.game.message.Message; import com.example.game.message.MessageA; import com.example.game.message.MessageB; ... @OnMessage public void message(Session session, Message msg) { if (msg instanceof MessageA) { // We received a MessageA object... else if (msg instanceof MessageB) { // We received a MessageB object... } }
エンドポイント・デプロイメントURIの一部をアプリケーション・パラメータとして指定する方法
ServerEndpoint
アノテーションを使用すると、レベル1のURIテンプレートを使用して、エンドポイント・デプロイメントURIの一部分をアプリケーション・パラメータとして指定できます。URIテンプレートでは、変数拡張を使用してURIの範囲を示します。
URIテンプレートの詳細は、http://tools.ietf.org/html/rfc6570
を参照してください。
エンドポイント・デプロイメントURIの一部をアプリケーション・パラメータとして指定するには:
例19-23は、エンドポイント・デプロイメントURIの一部をアプリケーション・パラメータとして指定する方法を示しています。
例19-23 エンドポイント・デプロイメントURIの一部をアプリケーション・パラメータとして指定する方法
この例では、エンドポイント・デプロイメントURIを、変数{room-name}
が含まれるURIテンプレートとして指定します。この変数は、open
メソッドのroomName
パラメータで拡張され、ユーザーがどのチャット・ルームに参加するかを決定します。
import javax.websocket.EndpointConfig; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/chatrooms/{room-name}") public class ChatEndpoint { @OnOpen public void open(Session session, EndpointConfig c, @PathParam("room-name") String roomName) { // Add the client to the chat room of their choice ... } ... }
{room-name}
変数を拡張するopen
メソッドの本文のコードは、この例には示していません。
ローカルのJava EEサーバーでポート8080を使用し、chatapp
というWebアプリケーション内にエンドポイントをデプロイしている場合、クライアントは次のURIを使用してエンドポイントに接続できます。
http://localhost:8080/chatapp/chatrooms/currentnews http://localhost:8080/chatapp/chatrooms/music http://localhost:8080/chatapp/chatrooms/cars http://localhost:8080/chatapp/chatrooms/technology
クライアントの状態の管理
コンテナでは、接続ごとにエンドポイント・クラスのインスタンスが作成されるので、クライアントの状態の情報を格納するためのインスタンス変数を定義して使用することができます。
また、Session.getUserProperties
メソッドには、ユーザー・プロパティを格納するための変更可能なマップが用意されています。
すべての接続クライアント共通の情報を格納するには、クラス(静的)変数を使用できますが、これらの変数へのスレッドセーフ・アクセスが保証されている必要があります。
例19-24は、クライアントの状態を保持する方法を示しています。
例19-24 クライアントの状態の保持
この例では、受信テキスト・メッセージに対して、各クライアントから受け取った直前のメッセージの内容を返します。
import java.io.IOException; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/delayedecho") public class DelayedEchoEndpoint { @OnOpen public void open(Session session) { session.getUserProperties().put("previousMsg", " "); } @OnMessage public void message(Session session, String msg) { String prev = (String) session.getUserProperties() .get("previousMsg"); session.getUserProperties().put("previousMsg", msg); try { session.getBasicRemote().sendText(prev); } catch (IOException e) { ... } } }
サーバー・エンドポイントのプログラムによる構成
Java API for WebSocketでは、コンテナでサーバー・エンドポイント・インタフェースを作成する方法を構成できます。
次に関して、エンドポイントを構成するカスタム・ロジックを提供できます。
-
WebSocket接続のハンドシェイク・リクエストの詳細へのアクセス
-
Origin
HTTPヘッダーのカスタム・チェックの実行 -
WebSocketハンドシェイク・レスポンスの変更
-
クライアントから要求されるWebSocketサブプロトコルの選択
-
エンドポイント・インスタンスのインスタンス化と初期化の制御
-
サーバー・エンドポイントでサポートされる拡張機能の指定
プログラムを使用してサーバー・エンドポイントを構成するには:
例19-25 ServerEndpointConfig.Configuratorクラスの拡張
この例では、ServerEndpointConfig.Configurator
クラスを拡張して、ハンドシェイク・リクエスト・オブジェクトをエンドポイント・インスタンスで使用できるようにします。
import javax.websocket.HandshakeResponse; import javax.websocket.server.ServerEndpointConfig.Configurator; import javax.websocket.server.HandshakeRequest; ... public class CustomConfigurator extends ServerEndpointConfig.Configurator { @Override public void modifyHandshake(ServerEndpointConfig conf, HandshakeRequest req, HandshakeResponse resp) { conf.getUserProperties().put("handshakereq", req); } ... }
例19-26 サーバー・エンドポイント・クラスのカスタム・コンフィギュレータの指定
この例では、カスタム・コンフィギュレータ・クラスCustomConfigurator.class
を、サーバー・エンドポイント・クラスMyEndpoint
に指定します。
カスタム・コンフィギュレータを使用すると、サーバー・エンドポイント・クラスのインスタンスがハンドシェイク・リクエスト・オブジェクトにアクセスできるようになります。サーバー・エンドポイント・クラスは、ハンドシェイク・リクエスト・オブジェクトを使用して、ハンドシェイク・リクエストの詳細(ヘッダーやHttpSession
オブジェクトなど)にアクセスします。
import javax.websocket.EndpointConfig; import javax.websocket.HandshakeResponse; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpoint; import java.util.List; import java.util.Map; ... @ServerEndpoint( value = "/myendpoint", configurator = CustomConfigurator.class ) public class MyEndpoint { @OnOpen public void open(Session s, EndpointConfig conf) { HandshakeRequest req = (HandshakeRequest) conf.getUserProperties() .get("handshakereq"); Map<String,List<String>> headers = req.getHeaders(); ... } }
Java API for WebSocketを使用するアプリケーションの構築
Java API for WebSocketはwlserver/server/lib/api.jar
ファイル内に用意されています。Java API for WebSocketを使用するアプリケーションを構築するには、アプリケーションのコンパイル時にクラスパスにこのライブラリを定義します。
Mavenを使用して、Java API for WebSocketを使用するアプリケーションを構築することもできます。Mavenを使用する場合は、Java API for WebSocketが格納されているMavenアーティファクト(javax.websocket.javax.websocket-api:1.0
)をMavenセントラルから取得します。詳細は、「WebLogic Mavenプラグインの使用方法」を参照してください。
WebSocketアプリケーションのデプロイ
WebLogic Serverでは、標準のJava EE Webアプリケーション・アーカイブ(WAR)の一部としてWebSocketアプリケーションをデプロイします。これは、スタンドアロンのWebアプリケーションまたはエンタープライズ・アプリケーション内のWARモジュールのいずれかとして行います。
web.xml
ファイルやその他のデプロイメント記述子でWebSocketエンドポイントを構成したり、WebSocketエンドポイントを登録または有効にするために動的な操作を実行する必要はありません。
ただしオプションで、表19-3に表示されているコンテキスト初期化プロパティを設定できます。これらのプロパティがWebLogic Server固有で、JSR 356の仕様に含まれていないことを示すため、それぞれの完全修飾名には接頭辞weblogic.websocket
が付いています。
表19-3 WebSocketアプリケーションのコンテキスト初期化プロパティ
プロパティ | タイプ | 説明 |
---|---|---|
|
|
メッセージ受信用の内部の最大バッファ・サイズ(バイト)。アプリケーションは、このサイズを超えるメッセージを処理できません。 このパラメータは、次のサーバー・セッションおよびクライアント・セッションに影響します。
デフォルトのバッファ・サイズは4194315 (ペイロードに4MB、フレームのオーバーヘッドに11バイト)です。 |
|
|
接続のアイドル・タイムアウト後の最大時間(ミリ秒)デフォルト値は30000 (30秒に相当)です。 |
|
|
WebSocketクラスタでは、Coherenceを実装の一部に使用して、クラスタ内のすべてのメンバー間の通信を確立します。WebSocketクラスタ化を使用すると水平スケーリングが可能になり、メッセージをクラスタのすべてのメンバーに送信したり、接続したクライアントの最大数を増やしたり、ブロードキャストの実行時間を短縮したりできます。クラスタ化は、デフォルトで無効になっています。 クラスタ化を有効にするには、値をtrueに設定します。 |
例19-27は、WebSocketアプリケーションにコンテキスト初期化プロパティを設定する方法を示しています。
例19-27 WebSocketアプリケーションのコンテキスト初期化プロパティの設定
この例では、WebSocketアプリケーションにコンテキスト初期化パラメータを次のように設定します。
-
メッセージ受信用の内部の最大バッファ・サイズを16777227バイトに設定します。
-
接続のアイドル・タイムアウト後の最大時間を60,000ミリ秒(1分に相当)に設定します。
-
WebSocketクラスタを有効にするには、管理対象Coherenceサーバーを使用して、すべてのメンバー間の通信を確立します。
ノート:
クラスタ化には、ローカル・ストレージが有効な管理対象Coherenceサーバーが必要です。『Oracle WebLogic Serverクラスタの管理』のCoherenceクラスタ・メンバーのストレージ設定の構成に関する項を参照してください。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" ...> ... <context-param> <param-name>weblogic.websocket.tyrus.incoming-buffer-size</param-name> <param-value>16777227</param-value> </context-param> <context-param> <param-name>weblogic.websocket.tyrus.session-max-idle-timeout</param-name> <param-value>60000</param-value> </context-param> <context-param> <param-name>weblogic.websocket.tyrus.cluster </param-name> <param-value>true</param-value> </context-param> </web-app>
WebSocketアプリケーションの監視
WebSocketアプリケーションおよびエンドポイントのメッセージ統計およびランタイム・プロパティを監視できます。エンドポイント・レベルでの監視は個々のエンドポイントごとに情報を収集し、一方、アプリケーション・レベルでの監視は指定されたアプリケーションで内デプロイしているすべてのエンドポイントからの情報を集約します。
WebSocket監視プロパティ
次の表には、実行時に監視されるプロパティのタイプの詳細と監視がアプリケーション・レベルまたはエンドポイント・レベルのいずれで起こるかが示されています。メッセージ関連プロパティでは、WebLogic Serverはメッセージ・サイズにバイトを使用し、テキスト、バイナリおよびコントロールの3つのタイプのメッセージ・テキストを区別します。
プロパティ | 説明 | 監視レベル |
---|---|---|
オープン・セッション数 |
WebSocketアプリケーションまたはエンドポイントの現行オープン・セッションの数。 |
アプリケーション、エンドポイント |
最大オープン・セッション数 |
サーバー起動以来のWebSocketアプリケーションまたはエンドポイントのオープン・セッションの最大数。 |
アプリケーション、エンドポイント |
エラー数 |
各エラーが発生した回数を示したエラーのリスト。エラーはスローできるクラス名で表されます。 |
アプリケーション、エンドポイント |
送信メッセージ数 |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントに送信されたメッセージの数。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
受信メッセージ数 |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントが受信したメッセージの数。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
送信メッセージ数/秒 |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントに送信された1秒当たりのメッセージの数。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
受信メッセージ数/秒 |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントが受信した1秒当たりのメッセージの数。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
最小送信メッセージ・サイズ |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントに送信されたメッセージの最小サイズ。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
最小受信メッセージ・サイズ |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントが受信したメッセージの最小サイズ。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
最大送信メッセージ・サイズ |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントに送信されたメッセージの最大サイズ。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
最大受信メッセージ・サイズ |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントが受信したメッセージ最大サイズ。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
平均送信メッセージ・サイズ |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントに送信されたメッセージの平均サイズ。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
平均受信メッセージ・サイズ |
監視が始まった時点からWebSocketアプリケーションまたはエンドポイントが受信したメッセージの平均サイズ。 統計は個々のメッセージ・タイプ(テキスト、バイナリおよびコントロール)ごと、および合計数として表示されます。 |
アプリケーション、エンドポイント |
エンドポイント・パス |
アプリケーション・コンテキスト・ルートに対するエンドポイントが登録されたパス。 |
エンドポイントのみ |
エンドポイント・クラス名 |
エンドポイント・クラスの名前。 |
エンドポイントのみ |
-
Oracle WebLogic Server管理コンソール・オンライン・ヘルプのWebSocketアプリケーションの監視に関する項
プロキシ・サーバーでのWebSocketの使用
WebSocketアプリケーションにアクセスするクライアントは、WebLogic Serverインスタンスに直接接続するか、またはWebSocketプロトコルをサポートするWebプロキシ・サーバーを介して接続する必要があります。
次のプロキシ・サーバーはWebSocketプロトコルをサポートします。
-
Oracle HTTP Server
-
Oracle WebLogic Serverプロキシ・プラグインとともに使用される場合のApache HTTPサーバー
Oracle WebLogic Serverプロキシ・プラグインとともに使用する場合にサポートされる特定のバージョンのApache HTTPサーバーの詳細は、Oracle Technology NetworkのOracle Fusion Middlewareのサポートされるシステム構成を参照してください。
WebSocketクライアントの記述
通常、WebSocketクライアント・アプリケーションはブラウザ・ベースのクライアントです。Java API for WebSocketは、Java WebSocketクライアントの記述にも使用できます。
ブラウザ・ベースのWebSocketクライアントの記述
ブラウザ・ベースのWebSocketクライアント・アプリケーションは、通常、HTML5技術(HTMLマークアップ、CSS3、WebSocket JavaScript APIを利用するJavaScriptなど)の複合体です。HTML5の詳細は、http://www.w3.org/TR/html5/
を参照してください。
ほとんどのブラウザでは、WebSocketプロトコルを作成して動かすために使用できるW3C WebSocket APIをサポートしています。W3C WebSocket APIの詳細は、http://www.w3.org/TR/websockets/
を参照してください。
実行時環境でWebSocketプロトコルのサポートが保証されていない場合は、ブラウザ・ベースのクライアントでJavaScript API for WebSocketのフォールバックを使用してください。このAPIは、標準のW3C WebSocket API実装を提供します。また、このAPIは、WebSocketプロトコルがサポートされていない場合に、WebSocketメッセージングの代替転送方法を使用するためのメカニズムも提供します。詳細は、「WebSocketメッセージングのプロトコル・フォールバックの有効化」を参照してください。
次のステップは、WebSocketプロトコルを使用してWebLogic Serverインスタンスにメッセージを送信する、クライアント上の実行フローの例を示しています。
親トピック: WebSocketクライアントの記述
Java WebSocketクライアントの記述
javax.websocket
パッケージには、クライアントとサーバーのエンドポイントに共通のアノテーション、クラス、インタフェースおよび例外が含まれています。このパッケージのAPIを使用して、サーバーを記述する場合と同じようにJava WebSocketクライアントを記述します。クライアントの記述に固有の追加のプログラミング・タスクについては、後続の項で説明します。
- WebSocketクライアント・エンドポイントのプログラムによる構成
- Java WebSocketクライアントのサーバー・エンドポイントへの接続
- WebSocketクライアントからメッセージをディスパッチするためのスレッドの最大数の設定
親トピック: WebSocketクライアントの記述
WebSocketクライアント・エンドポイントのプログラムによる構成
WebLogic Serverには、コンテナでクライアント・エンドポイント・インタフェースを作成する方法を構成するプロパティが用意されています。これらのプロパティがWebLogic Server固有で、JSR 356の仕様に含まれていないことを示すため、それぞれの完全修飾名には接頭辞weblogic.websocket
が付いています。
WebLogic Serverは次のプロパティを提供します。
-
HTTPプロキシ構成。WebSocketプロトコル(RFC 6455)で定義されているように、WebLogic Serverでは、HTTPプロキシ経由でリモート・サーバーのWebSocketエンドポイントにクライアント接続できます。
HTTPプロキシ構成プロパティを表19-4に示します。
-
Secure Sockets Layer (SSL)構成。WebLogic Serverでは、wssスキームを使用してSSL経由でリモート・サーバーのWebSocketエンドポイントにクライアント接続できます。
SSL構成プロパティを表19-5に示します。
-
受信メッセージのバッファ・サイズ。WebLogic Serverでは、WebSocketクライアント・エンドポイントの受信メッセージのサイズを制限できます。
バッファ・サイズ構成プロパティを表19-6に示します。
表19-4 Java WebSocketクライアントのHTTPプロキシ構成プロパティ
プロパティ | タイプ | 説明 |
---|---|---|
|
|
HTTPプロキシ・ホストの名前。JavaScriptクライアントのプロキシ設定を構成する場合は、このプロパティを指定する必要があります。 |
|
|
オプション。HTTPプロキシ・ホストへの接続に使用するポート番号。ポート番号なしでHTTPプロキシ・ホストを指定する場合、ポート番号はデフォルトの80になります。 |
|
|
オプション。プロキシ・ホストにログインするためのユーザー名。 |
|
|
オプション。プロキシ・ホストにログインするためのユーザー名。 |
表19-5 Java WebSocketクライアントのSSL構成プロパティ
プロパティ | タイプ | 説明 |
---|---|---|
|
|
オプション。サポートされているSSLプロトコル・バージョンのカンマ区切りリスト。 |
|
|
オプション。キーストア・ファイル(SSL暗号化で使用するセキュリティ証明書を格納)へのパス。 |
|
|
オプション。キーストアのパスワード。 |
表19-6 Java WebSocketクライアントのバッファ・サイズ構成プロパティ
プロパティ | タイプ | 説明 |
---|---|---|
|
|
メッセージ受信用の内部の最大バッファ・サイズ(バイト)。クライアントは、このサイズを超えるメッセージを処理できません。 このプロパティが設定されている場合は、表19-3に表示された同じ名前のコンテキスト初期化プロパティの値がオーバーライドされます。 デフォルトのバッファ・サイズは4194315 (ペイロードに4MB、フレームのオーバーヘッドに11バイト)です。 |
ノート:
クライアント・エンドポイントは、クライアントをサーバー・エンドポイントに接続する前に構成してください。
プログラムを使用してWebSocketクライアント・エンドポイントを構成するには:
-
javax.websocket.ClientEndpointConfig
オブジェクトを取得します。-
javax.websocket.ClientEndpointConfig.Builder.create
静的メソッドを呼び出して、ClientEndpointConfig.Builder
クラスのインスタンスを取得します。 -
前のステップで取得した
ClientEndpointConfig.Builder
オブジェクト上で、build
メソッドを呼び出します。
-
-
変更する各構成プロパティを新しい値に設定します。
-
前のステップで取得した
ClientEndpointConfig
オブジェクト上でgetUserProperties
メソッドを呼び出し、ユーザー・プロパティが格納された変更可能なjava.util.Map
オブジェクトを取得します。 -
前のステップで取得した
Map
オブジェクト上で、put
メソッドを呼び出します。put
メソッドの呼出しでは、プロパティ名とその新しい値をパラメータとしてメソッドに提供します。
-
例19-28は、プログラムを使用してWebSocketクライアント・エンドポイントを構成する方法を示しています。
例19-28 WebSocketクライアント・エンドポイントのプログラムによる構成
この例では、プログラムを使用してWebSocketクライアント・エンドポイントを次のように構成します。
-
HTTPプロキシ・ホスト名を
proxy.example.com
に設定します。 -
HTTPプロキシ・ホストへの接続に使用するポート番号を80に設定します。
-
キーストア・ファイルへのパスを
/export/keystore
に設定します。 -
キーストアのパスワードを
keystore_password
に設定します。 -
メッセージ受信用の内部の最大バッファ・サイズを16777227バイト(ペイロードに16MB、フレームのオーバーヘッドに11バイト)に設定します。
... import javax.websocket.ClientEndpointConfig; ... ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build(); // configure the proxy host cec.getUserProperties().put("weblogic.websocket.client.PROXY_HOST", "proxy.example.com"); // configure the proxy port cec.getUserProperties().put("weblogic.websocket.client.PROXY_PORT", 80); // configure the trust keystore path cec.getUserProperties().put("weblogic.websocket.client.SSL_TRUSTSTORE", "/export/keystore"); // configure the trust keystore's password cec.getUserProperties().put("weblogic.websocket.client.SSL_TRUSTSTORE_PWD", "keystore_password"); // for receiving 16 Mbyte payload cec.getUserProperties().put("weblogic.websocket.tyrus.incoming-buffer-size", 16 * 1024 * 1024 + 11); ...
親トピック: Java WebSocketクライアントの記述
Java WebSocketクライアントのサーバー・エンドポイントへの接続
Java WebSocketクライアントをサーバー・エンドポイントに接続するには:
例19-4は、Java WebSocketクライアントをサーバー・エンドポイントに接続する方法を示しています。
例19-29 Java WebSocketクライアントのサーバー・エンドポイントへの接続
この例では、Java WebSocketクライアントClientExample
をWebSocketサーバー・エンドポイント(ws://example.com:80/echoserver/echo
)に接続します。WebSocketクライアント・エンドポイントはクラスExampleEndpoint
で表現されます。ExampleEndpoint
クラスの宣言を例19-4に示します。
import java.io.IOException; import java.net.URI; import javax.websocket.CloseReason; import javax.websocket.ContainerProvider; import javax.websocket.Session; import javax.websocket.WebSocketContainer; ... public class ClientExample { public static void main(String[] args) throws Exception { WebSocketContainer container = ContainerProvider.getWebSocketContainer(); Session session = container.connectToServer(ExampleEndpoint.class, new URI("ws://example.com:80/echoserver/echo")); ... session.close(); }
親トピック: Java WebSocketクライアントの記述
WebSocketクライアントからメッセージをディスパッチするためのスレッドの最大数の設定
デフォルトで、WebSocketクライアントからメッセージをディスパッチするための最大スレッド数は、使用可能なプロセッサの数によって異なります。
-
使用可能なプロセッサ数が20以下の場合、最大スレッド数は20です。
-
使用可能なプロセッサ数が20を超える場合、最大スレッド数は使用可能なプロセッサ数と同数です。
WebSocketクライアントからメッセージをディスパッチするための最大スレッド数を設定するには:
- クライアント・アプリケーションを起動する
java
コマンドで、システム・プロパティweblogic.websocket.client.max-aio-threads
を必要な数に設定します。
例19-30は、WebSocketクライアントからメッセージをディスパッチするための最大スレッド数を設定する方法を示しています。
例19-30 WebSocketクライアントからメッセージをディスパッチするための最大スレッド数の設定
この例では、WebSocketクライアントClientExample
からメッセージをディスパッチするための最大スレッド数を50に設定します。
java -Dweblogic.websocket.client.max-aio-threads=50 ClientExample
親トピック: Java WebSocketクライアントの記述
WebSocketアプリケーションの保護
WebLogic Serverでは、Webアプリケーション・アーカイブ(WAR)の一部としてWebSocketアプリケーションをデプロイします。これは、スタンドアロンのWebアプリケーションまたはエンタープライズ・アプリケーション内のWARモジュールのいずれかとして行います。したがって、Webアプリケーションの保護に適用する多くのセキュリティ上の措置を、WebSocketアプリケーションに適用することができます。
Webアプリケーションのセキュリティの詳細は、『WebLogicセキュリティ・サービスによるアプリケーションの開発』のセキュアなWebアプリケーションの開発に関する項を参照してください。
次の項では、WebLogic ServerにおけるWebSocketアプリケーションのセキュリティに関する考慮事項について説明します。
検証済の生成元ポリシーの適用
最新のブラウザでは、ある生成元からロードされたWebページ上で実行されているスクリプトが、別の生成元のリソースとやりとりしないようにするために、同一生成元ポリシーが使用されています。WebSocketプロトコル(RFC 6455)では、サーバーが生成元横断接続に同意するかどうかを決定できる、検証済の生成元ポリシーが使用されています。
スクリプトがWebSocketアプリケーションにオープニング・ハンドシェイク・リクエストを送信すると、WebSocketハンドシェイク・リクエストを使用してOrigin
HTTPヘッダーが送信されます。アプリケーションは、Origin
を検証しない場合、すべての生成元からの接続を受けれ入れます。予想される生成元以外の生成元からの接続を受け入れないようにアプリケーションを設定すると、WebSocketアプリケーションは、接続を拒否することができます。
javax.websocket.server.ServerEndpointConfig.Configurator
クラスを拡張することにより、WebSocketアプリケーションでOrigin
が確実に検証されるようにできます。
次のコード・サンプルは、検証済の生成元ポリシーを適用する方法を示しています。
... import javax.websocket.server.ServerEndpointConfig; public class MyConfigurator extends ServerEndpointConfig.Configurator { ... private static final String ORIGIN = "http://www.example.com:7001"; @Override public boolean checkOrigin(String originHeaderValue) { return ORIGIN.equals(originHeaderValue) } } ...
詳細は、「サーバー・エンドポイントのプログラムによる構成」を参照してください。
ノート:
ブラウザ以外のクライアント(Javaクライアントなど)では、WebSocketハンドシェイク・リクエストを使用してOrigin
HTTPヘッダーを送信する必要はありません。WebSocketハンドシェイク・リクエストにOrigin
ヘッダーが含まれない場合、リクエストはブラウザ以外のクライアントからのものであり、ハンドシェイク・リクエストにOrigin
ヘッダーが含まれる場合、ブラウザから、またはブラウザ以外のクライアントからの場合があります。
ブラウザ以外のクライアントが、Origin
ヘッダーを送信するかどうかは不定なため、ブラウザ以外のクライアントには、ブラウザ生成元セキュリティ・モデルは推奨さません。
親トピック: WebSocketアプリケーションの保護
WebSocketクライアントの認証と認可
WebSocketプロトコル(RFC 6455)では、ハンドシェイク処理時のWebSocketクライアントの認証方法を指定しません。標準のWebコンテナ認証および認可機能を使用すると、未認可のクライアントがサーバー上でWebSocket接続を開かないようにすることができます。
Webアプリケーションでサポートされている<auth-method>
要素の構成はすべて、WebSocketアプリケーションにも使用できます。これらの認証タイプとして、BASIC、FORM、CLIENT-CERTなどがあげられます。『WebLogicセキュリティ・サービスによるアプリケーションの開発』のセキュアなWebアプリケーションの開発に関する項を参照してください。
WebSocketアプリケーションのweb.xml
デプロイメント記述子ファイルで該当する<security-constraint>
要素を構成することにより、アプリケーション内のエンドポイントへのパスをセキュリティで保護することができます。クライアントは、<security-constraint>
を構成することで、WebSocketハンドシェイク・リクエストを送信する前に認証する必要があります。そうしない場合、サーバーはWebSocketハンドシェイク・リクエストを拒否します。<security-constraint>
要素の詳細は、『Oracle WebLogic Server Webアプリケーション、サーブレット、JSPの開発』のweb.xmlデプロイメント記述子要素に関する項を参照してください。
次のコード・サンプルは、アプリケーション内のエンドポイントへのパスをセキュリティで保護する方法を示しています(ここで、パスは/demo
です)。
<security-constraint> <web-resource-collection> <web-resource-name>Secured WebSocket Endpoint</web-resource-name> <url-pattern>/demo</url-pattern> <http-method>GET</http-method> </web-resource-collection> <auth-constraint> <role-name>user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/login.jsp</form-login-page> <form-error-page>/error.jsp</form-error-page> </form-login-config> </login-config> <security-role> <role-name>user</role-name> </security-role>
WebSocketクライアントの認証
BASICおよびDIGEST認証方式を実装し、javax.websocket.ClientEndpointConfig.Configurator
クラスを使用してハンドシェイクのメッセージ・ヘッダーを操作することにより特定のクライアントを許可するように、WebSocketアプリケーションを構成できます。クライアントがWebSocket接続を作成することをアプリケーションが認可しない場合、サーバーはそのクライアントからのWebSocketハンドシェイク・リクエストを拒否します。
ハンドシェイクのオープン時にクライアントから渡されたOriginヘッダーの値をチェックするには、javax.websocket.server.ServerEndpointConfig.Configurator
クラスのcheckOrigin
メソッドを使用します。カスタム・チェックを使用する場合は、このメソッドをオーバーライドできます。詳細は、「サーバー・エンドポイントのプログラムによる構成」を参照してください。
認証用のJSR356コード・サンプルが必要です。
親トピック: WebSocketクライアントの認証と認可
セキュアなWebSocket接続の確立
WebSocket接続を確立するために、クライアントはハンドシェイク・リクエストをサーバーに送信します。ws
スキームを使用してWebSocket接続を開く場合、ハンドシェイク・リクエストはプレーンHTTPリクエストになります。確立されたWebSocket接続を介して転送されるデータは暗号化されません。
セキュアなWebSocket接続を確立し、データがインターセプトされないようにするには、WebSocketアプリケーションが、wss
スキームを使用する必要があります。wss
スキームを使用すると、クライアントがハンドシェイク・リクエストをHTTPSリクエストとして送信し、転送データがTLS/SSLで暗号化されます。
HTTPSハンドシェイク・リクエストのみを受け入れるようにWebSocketアプリケーションを構成することができます。この場合、すべてのWebSocket接続を暗号化する必要があり、暗号化されていないWebSocketハンドシェイク・リクエストは拒否されます。WebSocketアプリケーションのweb.xml
デプロイメント記述子ファイルで<user-data-constraint>
要素を指定します。<user-data-constraint>
要素の詳細は、『Oracle WebLogic Server Webアプリケーション、サーブレット、JSPの開発』のweb.xmlデプロイメント記述子要素に関する項を参照してください。
次のコード・サンプルは、<user-data-constraint>
要素の構成方法を示しています。
<security-constraint> <web-resource-collection> <web-resource-name>Secured WebSocket Endpoint</web-resource-name> <url-pattern>/demo</url-pattern> <http-method>GET</http-method> </web-resource-collection> <auth-constraint> <role-name>user</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>
親トピック: WebSocketアプリケーションの保護
複合コンテンツの回避
スクリプトではws://
URI (プレーンHTTPリクエストを使用)を通してWebSocket接続を開こうとし、一方でトップレベルのWebページがHTTPSリクエストを通して取得される場合、そのWebページは複合コンテンツと呼ばれます。ほとんどのブラウザは複合コンテンツを許可しなくなっていますが、まだ許可しているものもあります。WebSocketアプリケーションでは混合コンテンツを回避する必要があります。なぜなら、これによってJSESSIONID
やCookieなどの保護する必要がある特定の情報の公開が可能になるからです。
混合コンテンツの詳細は、http://www.w3.org/TR/wsc-ui/#securepage
のWeb Security Context: User Interface Guidelinesを参照してください。
親トピック: WebSocketアプリケーションの保護
WebSocket接続に対する制限の指定
WebSocket接続に制限を指定すると、クライアントによってサーバーのリソース(メモリーやソケットなど)が使い果されてしまうことを回避できます。
WebSocket接続には次の制限を指定できます。
-
最大メッセージ・サイズ。WebSocket接続に最大メッセージ・サイズを設定するには、onMessage
アノテーションの
maxMessageSize要素をバイト単位のサイズに設定します。
-
アイドル・タイムアウト値。WebSocket接続にアイドル・タイムアウト値を設定するには、次のいずれかのメソッドを呼び出します。
-
個別の接続には、
Session
オブジェクトのsetMaxIdleTimeout
メソッドを呼び出します。 -
コンテナ全体では、
WebSocketContainer
オブジェクトのsetDefaultMaxSessionIdleTimeout
メソッドを呼び出します。
-
親トピック: WebSocketアプリケーションの保護
WebSocketメッセージングのプロトコル・フォールバックの有効化
プロトコル・フォールバックは、WebSocketプロトコルがサポートされていない場合に、WebSocketメッセージングの代替転送方法を使用するためのメカニズムを提供します。通常、WebSocketプロトコルがサポートされない理由は、WebSocketオブジェクトが使用できないためか、WebSocketフレームがファイアウォールによってブロックされているためです。このリリースでサポートされている代替転送方法は、HTTPロング・ポーリングのみです。
プロトコル・フォールバックを使用すると、実行時環境でWebSocketプロトコルがサポートされているかどうかにかかわらず、標準のプログラミングAPIを使用してWebSocketメッセージングを実行できます。
ノート:
WebSocketフォールバックをサポートするには、サーバーで固有のWebLogic Server WebSocket APIではなく、JSR 356 Java API for WebSocketを使用する必要があります。
クライアント・アプリケーションでJavaScript API for WebSocketフォールバックを使用する方法
JavaScript API for WebSocketのフォールバックは、標準のW3C WebSocket APIと追加のAPIの実装を提供するので、WebSocketフォールバックが簡単に行えます。JavaScript API for WebSocketのフォールバックの詳細は、『JavaScript API Reference for WebSocket Fallback』を参照してください。W3C WebSocket APIの詳細は、http://www.w3.org/TR/websockets/
を参照してください。
標準のW3C WebSocket JavaScript APIを使用する場合は、WebSocketプロトコルがサポートされているかどうか気にせずにアプリケーションのコードを記述できます。
WebSocketフォールバックの構成
WebLogic Serverには、WebSocketフォールバックを構成するプロパティが用意されています(表19-7を参照)。
表19-7 WebSocketフォールバックの構成プロパティ
プロパティ | タイプ | デフォルト | 説明 |
---|---|---|---|
|
string |
. |
|
|
integer |
0 |
デバッグ・レベル。 |
|
integer |
10 |
Internet Explorerブラウザのバージョンを示し、これよりも古い場合、フレーム・データにはBase16エンコーディングを使用します。 |
|
ブール |
いいえ |
Base16エンコーディングを使用するかどうかを示します。 |
|
integer |
2 |
特定の転送方法で接続を確立する最大連続再試行回数。 |
|
integer |
25000 |
サーバーに送信する連続ping間の時間間隔(ミリ秒)。 |
|
ブール |
true |
クライアントからサーバーへのping送信が有効かどうか。 |
|
string |
なし |
実行する転送方法(次のいずれかの転送方法):
|
|
integer |
1000 |
失敗した接続試行を同じ転送方法で再試行するまでの時間間隔(秒)。転送の再試行回数は増加しません。 この時間(ミリ秒)内での接続に失敗すると、再試行回数が1ずつ増加します。 |
|
integer |
1000 |
WebSocket接続の作成が失敗したと判断されるまでの時間(ミリ秒)。 |
WebSocketプロトコルを使用できる場合は、プロトコル・フォールバックが有効であっても、WebLogic Serverではこのプロトコルが使用されます。WebLogtic Serverでは、接続試行が失敗すると、TRY_AGAIN_INTERVAL
プロパティおよびNB_TRY_FOR_EACH_TRANSPORT
プロパティの値を次のように使用して、WebSocketプロトコルが使用可能かどうかを判断します。
-
TRY_AGAIN_INTERVAL
の時間(ミリ秒)内に接続が確立されない場合は、同じ転送方法で再試行されます。この転送の再試行回数は増加しません。 -
TRY_AGAIN_INTERVAL
の時間(ミリ秒)内での接続に失敗すると、再試行回数が1ずつ増加します。 -
再試行回数が
NB_TRY_FOR_EACH_TRANSPORT
の値に達すると、次の転送方法が試行されます。 -
最後の転送方法の再試行回数が
NB_TRY_FOR_EACH_TRANSPORT
の値に達すると、接続が閉じられます(つまり、クライアント上でonclose
関数がコールされます)。
WebSocketフォールバックを構成するには:
例19-31は、WebSocketフォールバックの構成方法を示しています。
例19-31 WebSocketフォールバックの構成
この例では、XMLHttpRequest
転送を実行して、デバッグ・レベルを10に設定し、クライアントからサーバーへのping送信を無効化します。
... try { var config = {}; config = { transport: XMLHttpRequest, debug: 10, SERVER_PING_ENABLED: false }; OraSocket.config(config); } catch (err) { console.log("Error creating WebSocket:" + JSON.stringify(err)); } ...
WebSocketオブジェクトの作成
WebSocketオブジェクトは、クライアントからリモート・ホストへのWebSocket接続を表します。
WebSocketオブジェクトを作成するには、WebSocket
コンストラクタを呼び出して、次の情報をパラメータとして渡します。
-
クライアントの接続先URL
-
(オプション) WebSocketフォールバックの構成設定が格納されているJSONオブジェクト
JSONオブジェクトの詳細は、「WebSocketフォールバックの構成」を参照してください。
例19-32は、WebSocketオブジェクトの作成方法を示しています。
表19-32 WebSocketオブジェクトの作成
この例では、WebSocketオブジェクトws
を作成します。例では、JavaScriptの標準関数を使用して、このコードが含まれているドキュメントのURLから、クライアントが接続するURLを判別します。
... var URI_SUFFIX = "/websocket-101/ws-101-app"; var ws; var connectionStatus = "Connecting..."; var calledBy = document.location.toString(); var machine, port, secured; var regExp = new RegExp("(http|ws)(.?):[/]{2}([^/|^:]*):?(\\d*)/(.*)"); var matches = regExp.exec(calledBy); secured = matches[2]; machine = matches[3]; port = matches[4]; ... statusFld = document.getElementById('status'); ... try { var wsURI = "ws" + secured + "://" + machine + ":" + port + URI_SUFFIX; ws = new WebSocket(wsURI); } catch (err) { var mess = 'WebSocket creation error:' + JSON.stringify(err); connectionStatus = "<font color='red'>Unable to connect.</font>"; if (statusFld !== undefined) statusFld.innerHTML = mess; else alert(mess); } ...
JavaScript WebSocketクライアントのライフサイクル・イベントの処理
JavaScript WebSocketクライアントのライフサイクル・イベントの処理には、WebSocket
オブジェクトのコールバック関数(表19-8を参照)の書込みを含みます。この表には、イベント・タイプ別の処理方法を示した例への相互参照も提供されています。
表19-8 ライフサイクル・イベントを処理するコールバック関数
イベント | コールバック関数 | 例 |
---|---|---|
Connection opened |
|
|
Message received |
|
|
Error |
|
|
Connection closed |
|
ノート:
この例で使用するws
WebSocket
オブジェクトの作成方法は、例19-32を参照してください。
例19-33 JavaScript WebSocketクライアントのConnection openedイベントの処理
この例では、JavaScriptの標準関数を使用して、接続が開いたときに現在の日付と時刻、メッセージConnection opened
を順に表示します。
... ws.onopen = function() { try { var text; try { text = 'Message:'; } catch (err) { text = '<small>Connected</small>'; } promptFld.innerHTML = text; if (nbMessReceived === 0) statusFld.innerHTML = ""; statusFld.innerHTML += ((nbMessReceived === 0?"":"<br>") + "<small>" + (new Date()).format("d-M-Y H:i:s._ Z") + "</small>:<font color='blue'>" + ' Connection opened.' + "</font>"); statusFld.scrollTop = statusFld.scrollHeight; nbMessReceived++; } catch (err) {} }; ...
例19-34 JavaScript WebSocketクライアントのMessage receivedイベントの処理
この例では、JavaScriptの標準関数を使用して、メッセージを受信したときに現在の日付と時刻、メッセージの内容を順に表示します。
... ws.onmessage = function(message) // message/event { var json = {}; if (typeof(message.data) === 'string') { try { json = JSON.parse(message.data); } catch (e) { console.log(e); console.log('This doesn\'t look like valid JSON: ' + message.data); } } if (json.type !== undefined && json.type === 'message' && typeof(json.appdata.text) === 'string') // it's a single message, text { var dt = new Date(); /** * Add message to the chat window */ var existing = contentFld.innerHTML; // Content already there var toDisplay = ""; try { toDisplay = json.appdata.text; } catch (err) {} contentFld.innerHTML = existing + ('At ' + + (dt.getHours() < 10 ? '0' + dt.getHours() : dt.getHours()) + ':' + (dt.getMinutes() < 10 ? '0' + dt.getMinutes() : dt.getMinutes()) + ': ' + toDisplay + '<br>'); contentFld.scrollTop = contentFld.scrollHeight; } else // Unexpected { var payload = {}; } }; ...
例19-35 JavaScript WebSocketクライアントのErrorイベントの処理
この例では、JavaScriptの標準関数を使用して、エラー発生時に現在の日付と時刻、エラー・メッセージを順に表示します。
... ws.onerror = function(error) { if (nbMessReceived === 0) statusFld.innerHTML = ""; statusFld.innerHTML += ((nbMessReceived === 0?"":"<br>") + "<small>" + (new Date()).format("d-M-Y H:i:s._ Z") + "</small>:<font color='red'>" + error.err + "</font>"); statusFld.scrollTop = statusFld.scrollHeight; nbMessReceived++; }; ...
例19-36 JavaScript WebSocketクライアントのConnection closedイベントの処理
この例では、JavaScriptの標準関数を使用して、接続が閉じたられたときに現在の日付と時刻、メッセージConnection closed
を順に表示します。
... ws.onclose = function() { if (nbMessReceived === 0) statusFld.innerHTML = ""; statusFld.innerHTML += ((nbMessReceived === 0?"":"<br>") + "<small>" + (new Date()).format("d-M-Y H:i:s._ Z") + "</small>:<font color='blue'>" + ' Connection closed' + "</font>"); promptFld.innerHTML = 'Connection closed'; }; ...
JavaScript WebSocketクライアントからのメッセージの送信
JavaScript WebSocketクライアントからメッセージを送信するには:
- メッセージ送信用の関数を定義します。
- メッセージ送信用の関数の本文内で、
WebSocket
オブジェクトのsend
関数をコールします。 - メッセージ送信用に定義した関数をコールします。
例19-37 メッセージ送信用の関数の定義
この例では、メッセージ送信用の関数send
を定義します。
この例で使用するws
WebSocket
オブジェクトの作成方法は、例19-32を参照してください。
... var send = function(mess) { ws.send(mess); }; ...
例19-38 メッセージ送信用の関数のコール
この例では、ユーザーが「Send」をクリックするとsend
関数がコールされ、テキスト・フィールドの内容が送信されます。
send
関数の定義方法は、例19-37を参照してください。
... <input type="text" id="input" style="border-radius:2px; border:1px solid #ccc; margin-top:10px; padding:5px; width:400px;" placeholder="Type your message here"/> <button onclick="javascript:send(document.getElementById('input').value);">Send</button> ...
WebSocketフォールバックのクライアント・ライブラリのパッケージ化と場所の指定
Webアプリケーションのscripts
ディレクトリにorasocket.min.js
ファイルをパッケージ化します。
クライアント・アプリケーションに次のscript
要素を追加して、orasocket.min.js
の場所を指定します。
<script type="text/javascript" src="scripts/orasocket.min.js"></script>
WebSocketフォールバックの有効化
デフォルトで、WebSocketフォールバックは無効になっています。
WebSocketフォールバックを有効化するには、アプリケーションのデプロイメント記述子ファイルweb.xml
でcom.oracle.tyrus.fallback.enabled
コンテキスト・パラメータをtrue
に設定します。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" ...> ... <context-param> <description>Enable fallback mechanism</description> <param-name>com.oracle.tyrus.fallback.enabled</param-name> <param-value>true</param-value> </context-param> </web-app>
非推奨のAPIからJSR 356 Java API for WebSocketへのアプリケーションの移行
使用中のWebSocketアプリケーションとWebLogic Serverの将来のリリースとの互換性を確保するには、非推奨になったパッケージのかわりにJSR 356 Java API for WebSocketを使用してください。
WebLogic Server 12.1.3以降、パッケージweblogic.websocket
およびweblogic.websocket.annotation
は非推奨となり、将来のリリースでは削除される予定です。これらのパッケージが削除された後は、WebSocketプロトコル経由の接続にこれらのパッケージを使用できなくなります。
JSR 356 APIと固有のWebLogic Server WebSocket APIとの比較
表19-9は、WebSocketアプリケーション開発タスクの実行で使用する固有のWebLogic Server WebSocket APIと、それに対応するJSR 356 APIを示しています。この表には、アノテーション付きエンドポイント用のJSR 356 APIのみが表示されています。また、タスク別に、JSR 356 APIを使用してタスクを実行するための操作手順への相互参照も提供されています。
表19-9 JSR 356 APIと固有のWebLogic Server WebSocket APIとの比較
タスク | 固有のWebLogic Server WebSocket API | JSR 356 API | 操作手順 |
---|---|---|---|
サーバー・エンドポイント・クラスの作成 |
|
|
|
Connection openedイベントの処理 |
|
イベントを処理するメソッドの |
|
Message receivedイベントの処理 |
|
イベントを処理するメソッドの |
|
Errorイベントの処理 |
|
イベントを処理するメソッドの |
|
Connection closedイベントの処理 |
|
イベントを処理するメソッドの |
|
メッセージの送信 |
|
|
|
エンドポイントに接続しているすべてのピアへのメッセージ送信 |
|
Session |
|
WebSocket接続の最大メッセージ・サイズの設定 |
|
onMessage |
|
WebSocket接続のアイドル・タイムアウト値の設定 |
|
次のうちいずれか:
|
|
WebSocket接続の最大オープン接続数の設定 |
|
JSR 356 Java API for Websocketではサポート対象外 |
固有のWebSocketサーバー・エンドポイントで使用するAPIをJSR 356 APIに変換する方法
固有のWebSocketサーバー・エンドポイントで使用するAPIをJSR 356 APIに変換するには:
-
WebSocket
クラスをアノテーション付きサーバー・エンドポイント・クラスに変換します。WebSocket
クラスからアノテーション付きエンドポイント・クラスへの変換は、WebSocket
クラスからプログラム的なエンドポイント・クラスへの変換よりも、変更が少なくて済みます。-
クラス宣言から
extends WebSocketAdapter
句またはimplements WebSocketListener
句を削除して、WebSocket
クラスをPOJOクラスに変換します。 -
クラス宣言の
weblogic.websocket.annotation.WebSocket
アノテーションをjavax.websocket.server.ServerEndpoint
アノテーションで置き換えます。詳細は、「アノテーション付きエンドポイントの作成」を参照してください。
ノート:
既存のエンドポイントの
pathPatterns
要素に/*
接尾辞が含まれている場合、/*
接尾辞と同じ結果が得られるようにコードを書き換える必要があります。詳細は、「パスのパターン文字列の/*接尾辞の置換え」を参照してください。
-
-
ライフサイクル・イベントを処理する各メソッドの宣言に、そのメソッドの処理対象であるイベントを指定するアノテーションを付けます。
詳細は、「アノテーション付きWebSocketエンドポイントでのライフサイクル・イベントの処理」を参照してください。
-
weblogic.websocket.WebSocketConnection
インタフェースへの各参照を、javax.websocket.Session
インタフェースへの参照で置き換えます。 -
WebSocketConnection
オブジェクト上の各メソッド呼出しを、Session
オブジェクト上の対応するメソッドの呼出しで置き換えます。たとえば、
WebSocketConnection
オブジェクトのclose
メソッドは、weblogic.websocket.ClosingMessage
オブジェクトをパラメータとして取得します。Session
オブジェクトのclose
メソッドで、これに対応するパラメータはjavax.websocket.CloseReason
オブジェクトです。 -
メッセージを送信するためには、
Session
オブジェクト上の各メソッドの呼出しを次のように変更します。-
getBasicRemote
メソッドまたはgetAsyncRemote
メソッドの呼出しを追加して、このエンドポイントのピアを表すオブジェクトへの参照を取得します。 -
非推奨になったAPIのメッセージ送信用のメソッドを、JSR 356 API.の対応するメソッドで置き換えます。
JSR 356 APIのメソッドは、前のステップで参照を取得した
javax.websocket.RemoteEndpoint.Basic
オブジェクトまたはjavax.websocket.RemoteEndpoint.Async
オブジェクトのメソッドです。詳細は、「メッセージの送信」を参照してください。
非推奨のAPIのメソッド RemoteEndpoint.Basicのメソッド RemoteEndpoint.Asyncのメソッド send(String message)
sendText(String text)
次のいずれかのメソッド:
sendText(String text)
sendText(String text, SendHandler handler)
send(byte[] message)
sendBinary
(ByteBuffer data)次のいずれかのメソッド:
sendBinary (ByteBuffer data)
sendBinary(ByteBuffer data, SendHandler handler)
sendPing(byte[] message)
sendPing(ByteBuffer applicationData)
sendPing(ByteBuffer applicationData)
sendPong(byte[] message)
sendPong(ByteBuffer applicationData)
sendPong(ByteBuffer applicationData)
stream(boolean last, String fragment)
sendText(String partialMessage, boolean isLast)
対応するメソッドはありません。
stream(boolean last, byte[] fragment, int off, int length)
sendBinary(ByteBuffer partialByte, boolean isLast)
対応するメソッドはありません。
-
-
import
句で、非推奨になったAPIのクラスに対する参照を、エンドポイントで使用しているJSR 356 APIのクラスに対する参照で置き換えます。 -
サーバー・エンドポイントを使用するアプリケーションを再コンパイルして再デプロイします。
パスのパターン文字列の/*接尾辞の置換え
非推奨になったAPIのWebSocket
アノテーションのpathPatterns
要素では、パスのパターン文字列で/*
接尾辞を使用できます。/*
接尾辞を使用すると、/*
接尾辞の前に記述されたパス・パターンで始まるすべてのリソース・パスとパス・パターンが照合されます。たとえば、リソース・パス/ws/chat
は、パス・パターン/ws/*
に一致します。
JSR 356 APIには、/*
接尾辞に相当する機能はありません。既存のエンドポイントで/*
接尾辞が使用されている場合、/*
接尾辞と同じ結果が得られるようにコードを書き換える必要があります。コードの書換え方法は、/*
接尾辞がエンドポイントURIの変数パス・パラメータを表しているのか、エンドポイントの追加データを表しているのかによって異なります。
エンドポイントURIの変数パス・パラメータを表す/*接尾辞の置換え
パスのパターン文字列の/*
接尾辞は、エンドポイントURIの1つ以上の変数パス・パラメータを表している場合があります。このような場合は、/*
接尾辞のかわりにURIテンプレートを使用します。
JSR 356 APIではレベル1のURIテンプレートのみをサポートし、そこではパス・パラメータはスラッシュ(/
)で明確に区切られます。したがって、URIテンプレートでは、既存のエンドポイントの/*
接尾辞にかわる変数パス・パラメータごとに1つの拡張変数を定義する必要があります。
たとえば、既存のエンドポイントの/*
接尾辞を1つの変数パス・パラメータで置き換える場合は、次の例で示すようにURIテンプレートを定義します。
/ws/{param1}
URI /ws/test
は、前の例のテンプレートに一致します。param1
変数はtest
に拡張されます。
同様に、既存のエンドポイントの/*
接尾辞を2つの変数パス・パラメータで置き換える場合は、次の例で示すようにURIテンプレートを定義します。
/ws/{param1}/{param2}
URI /ws/test/chat
は、前の例のテンプレートに一致します。param1
変数はtest
に、param2
変数はchat
にそれぞれ拡張されます。
詳細は、「エンドポイント・デプロイメントURIの一部をアプリケーション・パラメータとして指定する方法」を参照してください。
親トピック: パスのパターン文字列の/*接尾辞の置換え
エンドポイントの追加データを表す/*接尾辞の置換え
パスのパターン文字列の/*
接尾辞は、URIの一部として転送される、エンドポイントの追加情報を表している場合があります。このような場合は、/*
接尾辞のかわりに問合せパラメータを使用します。
JSR 356の仕様では、問合せパラメータの使用が禁止されたり制限されることはありません。したがって、次の条件を満たせば、問合せパラメータを使用して任意のデータを転送できます。
-
URLの長さが最大許容長より短いこと。
-
すべてのデータが適切にエンコードされていること。
エンドポイントの問合せパラメータを取得するには、必要な形式でパラメータを取得できる、エンドポイントのSession
オブジェクトのメソッドを呼び出します。
-
問合せ全体が含まれている単一の文字列としてパラメータを取得するには、
getQueryString
メソッドを呼び出します。例19-39を参照してください。 -
問合せパラメータのリストが含まれているマップとしてパラメータを取得するには、
getRequestParameterMap
メソッドを呼び出します。例19-40を参照してください。
例19-39 問合せパラメータを単一の文字列として取得する方法
この例では、リクエストURI /echo?foo=bar,baz,mane,padme,hum
の問合せパラメータをアプリケーション出力"# foo=bar,baz,mane,padme,hum"
として取得します。
import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; ... @ServerEndpoint("/echo") public class EchoEndpoint { @OnOpen public void onOpen(Session session) throws IOException { System.out.println("# " + session.getQueryString()); } // ... }
例19-40 問合せパラメータをマップとして取得する方法
この例では、リクエストURI /echo?foo=bar&foo=baz&foo=mane&foo=padme&foo=hum
の問合せパラメータをList<String>
# [bar, baz, mane, padme, hum]
として取得します。
import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpoint; import java.util.List; import java.util.Map; ... @ServerEndpoint("/echo") public class EchoEndpoint { @OnOpen public void onOpen(Session session) throws IOException { System.out.println("# " + session.getRequestParameterMap().get("foo")); } // ... }
親トピック: パスのパターン文字列の/*接尾辞の置換え
固有のWebSocketサーバー・エンドポイントで使用するAPIをJSR 356 APIに変換する例
例19-41は、固有のWebSocketサーバー・エンドポイントで使用するAPIを、非推奨になったAPIからJSR 356 APIに変換する方法を示しています。
例19-41 WebSocketサーバー・エンドポイントで使用するAPIをJSR 356 APIに変換する方法
この例では、WebSocketサーバー・エンドポイントで使用するAPIを、非推奨になったAPIからJSR 356 APIに変換する場合に必要な変更を示します。
この例では、非推奨になったコードの行は//
コメント文字を使用してコメント・アウトされています。JSR 356 APIのコード行は、コメント//JSR 356
で示しています。
package examples.webapp.html5.websocket; //import weblogic.websocket.ClosingMessage; Deprecated //import weblogic.websocket.WebSocketAdapter; Deprecated //import weblogic.websocket.WebSocketConnection; Deprecated //import weblogic.websocket.annotation.WebSocket; Deprecated import javax.websocket.CloseReason; //JSR 356 import javax.websocket.OnMessage; //JSR 356 import javax.websocket.Session; //JSR 356 import javax.websocket.server.ServerEndpoint; //JSR 356 import java.io.IOException; //@WebSocket( Deprecated // timeout = -1, Deprecated // pathPatterns = {"/ws"} Deprecated //) @ServerEndpoint("/ws") //JSR 356 //public class MessageListener extends WebSocketAdapter { Deprecated public class MessageListener { //@Override Not required. Replaced by @OnMessage in a POJO class @OnMessage //JSR 356 //public void onMessage(WebSocketConnection connection, String payload) { Deprecated public void onMessage(Session connection, String payload) //JSR 356 throws IOException { //JSR 356 // Sends message from the browser back to the client. String msgContent = "Message \"" + payload + "\" has been received by server."; try { // connection.send(msgContent); Deprecated connection.getBasicRemote().sendText(msgContent); //JSR 356 } catch (IOException e) { // connection.close(ClosingMessage.SC_GOING_AWAY); Deprecated connection.close(new //JSR 356 CloseReason(CloseReason.CloseCodes.GOING_AWAY, "Going away.")); //JSR 356 } } }
WebLogic ServerでのJava API for WebSocketの使用例
ユーザーがクライアントから送信したテキストを、サーバー・エンドポイントでエコーする例について検討します。ユーザーがテキスト・メッセージを送信すると、サーバーはそのメッセージにテキスト(from your server)を追加してユーザーにメッセージを返信します。
例19-42 WebLogic ServerでのJava API for WebSocketの使用方法
package com.example.websocket.sample.echo; import java.io.IOException; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/echo") public class EchoEndpoint { @OnOpen public void onOpen(Session session) throws IOException { session.getBasicRemote().sendText("onOpen is invoked."); } @OnMessage public String echo(String message) { return message + " (from server)"; } @OnError public void onError(Throwable t) { t.printStackTrace(); } }