001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.hayabusa.servlet; 017 018import java.net.URI; 019 020import javax.websocket.ClientEndpoint; 021import javax.websocket.ContainerProvider; 022import javax.websocket.OnClose; 023import javax.websocket.OnError; 024import javax.websocket.OnMessage; 025import javax.websocket.OnOpen; 026import javax.websocket.Session; 027import javax.websocket.CloseReason; 028import javax.websocket.EndpointConfig; 029import javax.websocket.WebSocketContainer; 030import javax.websocket.DeploymentException; 031 032import javax.websocket.ClientEndpointConfig; 033import javax.websocket.Endpoint; 034import javax.xml.bind.DatatypeConverter; 035import java.util.Map; 036import java.util.List; 037import java.util.Arrays; 038import java.io.IOException; 039 040/** 041 * Websocket Endpoint implementation class WebSocketClient 042 * 043 * Client を実行するには、%CATALINA_HOME%/lib/websocket-api.jar ではだめです。 044 * META-INF\services\javax.websocket.ContainerProvider に、Provider を 045 * 記述しておく必要があるそうです。 046 * 047 * 方法としては、 048 * ① tyrus-standalone-client-jdk-1.13.1.jar を使用する。 049 * ② %CATALINA_HOME%/lib/tomcat-websocket.jar を使用する。 050 * この場合、依存関係で、/lib/tomcat-util.jar 、bin/tomcat-juli.jar も 051 * 使用します。 052 * ※ 今現在、java Client は動いていません。 053 * 054 */ 055 056@ClientEndpoint 057public class WebSocketClient extends Endpoint { 058 059 /** 060 * デフォルトコンストラクター 061 * 062 */ 063 public WebSocketClient() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 064 065 /** 066 * サーバーからの通知受信のためのコールバック 067 * 068 * 引数は以下が設定可能だが、メソッド内で使用しないなら省略できる。 069 * 070 * @param session サーバーの接続情報 071 * @param config 設定情報 072 */ 073 @OnOpen 074 public void onOpen( final Session session, final EndpointConfig config ) { 075 /* セッション確立時の処理 */ 076 System.out.println("[セッション確立]"); 077 } 078 079 /** 080 * 5.テキストメッセージ受信時の処理 081 * 082 * 引数は使用しなければ省略可能。 083 * 084 * @param message サーバーから送信されたテキスト 085 * @param session 接続情報 086 */ 087 @OnMessage 088 public void onMessage( final String message , final Session session ) { 089 /* メッセージ受信時の処理 */ 090 System.out.println("[受信]:" + message); 091 } 092 093 /** 094 * 4.エラー時にコールされる。 095 * 096 * 引数は使用しなければ省略可能。 097 * 098 * @param session サーバーの接続情報 099 * @param th エラー 100 */ 101 @OnError 102 public void onError( final Session session , final Throwable th ) { 103 /* エラー発生時の処理 */ 104 System.out.println("[エラー発生]"); 105 } 106 107 /** 108 * 3.切断時にコールされる。 109 * 110 * 引数は使用しなければ省略可能。 111 * 112 * @param session サーバーの接続情報 113 * @param reason 切断理由 114 */ 115 @OnClose 116 public void onClose( final Session session, final CloseReason reason ) { 117 /* セッション解放時の処理 */ 118 System.out.println("[セッション解放]"); 119 } 120 121 /** 122 * メインメソッド。 123 * 124 * @param args 引数 125 * @throws DeploymentException WebSocketで、何らかの種類の障害が発生したことを示すチェック例外。 126 * @throws IOException なんらかの入出力例外の発生を通知するシグナルを発生させます。 127 * @throws InterruptedException スレッドで割り込みが発生した場合にスローされます。 128 */ 129 public static void main( final String[] args ) throws DeploymentException,IOException,InterruptedException { 130 // BASIC認証対応 131 final ClientEndpointConfig.Configurator configurator = new ClientEndpointConfig.Configurator() { 132 /** 133 * サーバーへの接続を開始するために使用されるハンドシェイク要求を作成した後で、要求の一部を送信する前に実装によって呼び出されます。 134 * @param headers 実装がハンドシェイクのやりとりを開始するために送信しようとしているハンドシェイク要求ヘッダーの可変マップ。 135 */ 136 @Override 137 public void beforeRequest( final Map<String, List<String>> headers ) { 138 headers.put("Authorization", Arrays.asList("Basic " + DatatypeConverter.printBase64Binary("admin:admin".getBytes()))); 139 } 140 }; 141 142 final ClientEndpointConfig clientConfig = ClientEndpointConfig.Builder.create() 143 .configurator(configurator) 144 .build(); 145 146 // 初期化のため WebSocket コンテナのオブジェクトを取得する 147 final WebSocketContainer container = ContainerProvider.getWebSocketContainer(); 148 // サーバー・エンドポイントの URI 149 final URI uri = URI.create( "ws://localhost:8826/gf/wsdemo?AAA=BBB" ); 150 // サーバー・エンドポイントとのセッションを確立する 151 final Session session = container.connectToServer( new WebSocketClient(),clientConfig,uri ); // BASIC認証対応 152 153 session.getBasicRemote().sendText("こんにちは"); 154 155 // 仮想マシンのシャットダウン・フックを登録(Ctrl-C で正常終了します) 156 Runtime.getRuntime().addShutdownHook( 157 new Thread( WebSocketClient.class.getName() ) { 158 /** 159 * runメソッド。 160 */ 161 @Override 162 public void run() { 163 // シャットダウン中は、LOGGER が実行されないようです。 164 System.out.println( "Shutdown WebSocketClient ..." ); 165 try { 166 session.close(); 167 } 168 catch( final Throwable th ) { 169 th.printStackTrace(); 170 } 171 } 172 } 173 ); 174 175 int cnt = 0; 176 while( session.isOpen() ) { 177 Thread.sleep( 10 * 1000 ); 178 System.out.println( "open " + cnt ); 179 session.getBasicRemote().sendText( "カウンター:" + (cnt++) ); 180 } 181 182 System.out.println( "Session closed." ); 183 session.close(); 184 } 185}