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}