    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}