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