    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.common;
    017
    018import java.util.Date;
    019import java.util.Map;
    020import java.util.EnumSet;
    021import java.io.IOException;
    022
    023import javax.servlet.ServletContextListener;
    024import javax.servlet.ServletContextEvent;
    025import javax.servlet.ServletContext;
    026import javax.servlet.ServletRegistration;
    027import javax.servlet.FilterRegistration;
    028import javax.servlet.DispatcherType;
    029import javax.servlet.annotation.WebListener;                            // 6.3.4.0 (2015/08/01)
    030
    031import org.apache.catalina.ContainerListener;                           // 6.3.9.0 (2015/11/06)
    032import org.apache.catalina.ContainerEvent;                                      // 6.3.9.0 (2015/11/06)
    033
    034import org.opengion.fukurou.db.ConnectionFactory;
    035import org.opengion.fukurou.util.Cleanable;
    036import org.opengion.fukurou.util.HybsEntry;
    037// import org.opengion.fukurou.util.URLConnect;                                 // 6.9.0.0 (2018/01/31) URLConnect 廃止
    038import org.opengion.fukurou.util.HttpConnect;                                   // 6.9.0.0 (2018/01/31) 新規追加
    039import org.opengion.fukurou.system.LogWriter;
    040
    041/**
    042 * ServletContextListener を実装した、コンテキストの監視オブジェクトです。
    043 * これは、コンテキスト(Webアプリケーション)の起動/シャットダウンを監視できる。
    044 *
    045 * ServletContextListener は、
    046 *
    047 *      ConnectionFactory のコネクションプールへのアクセス／開放
    048 *      ResourceFactory   のリソース情報へのアクセス／開放
    049 *
    050 * の作業を行います。
    051 *
    052 * このリスナーは、WEB-INF/web.xml で、組み込みます。
    053 *
    054 * 【WEB-INF/web.xml】
    055 *
    056 *     &lt;listener&gt;
    057 *         &lt;listener-class&gt;
    058 *             org.opengion.hayabusa.common.HybsContextListener
    059 *         &lt;/listener-class&gt;
    060 *     &lt;/listener&gt;
    061 *
    062 * @og.group 初期化
    063 *
    064 * @version  4.0
    065 * @author   Kazuhiko Hasegawa
    066 * @since    JDK5.0,
    067 */
    068@WebListener
    069public class HybsContextListener implements ServletContextListener , ContainerListener {
    070        // 4.0.0.0 (2007/10/26) ConnectionFactoryのhayabusa依存を切るために移動してきた
    071        static {
    072                final Cleanable clr = new Cleanable() {
    073                        /**
    074                         * 初期化(クリア)します。
    075                         * 主に、キャッシュクリアで利用します。
    076                         */
    077                        public void clear() {
    078                                ConnectionFactory.realClose();
    079                        }
    080                };
    081                SystemManager.addCleanable( clr );
    082        }
    083
    084        /**
    085         * デフォルトコンストラクター
    086         *
    087         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    088         */
    089        public HybsContextListener() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    090
    091        /**
    092         *  ServletContextListener インターフェースの実装
    093         *
    094         * Webアプリケーションがリクエストを処理できる状態になったことを
    095         * リスナーに通知する。
    096         *
    097         * @og.rev 3.0.0.0 (2002/12/25) バージョンチェック、HybsSystem初期化追加
    098         * @og.rev 3.4.0.0 (2003/09/01) Contextのpathによる、システムパラメータ の切り替え対応
    099         * @og.rev 3.4.0.3 (2003/09/10) ServletContext の名称を、仮想パス名とする。
    100         * @og.rev 3.5.3.1 (2003/10/31) システムパラメータ ファイルの読み取りタイミングを遅らせます。
    101         * @og.rev 4.0.0.0 (2005/01/31) Ver4 のシステムパラメータ情報の取得処理を追加します。
    102         * @og.rev 4.1.0.1 (2008/01/23) ログ出力先の設定処理を追加
    103         * @og.rev 4.3.4.1 (2008/12/08) ログの環境変数対応
    104         * @og.rev 6.3.8.3 (2015/10/03) プログラムによるWebアプリケーションの拡張
    105         * @og.rev 7.1.0.1 (2020/02/07) ログファイルのエンコードを SYS_LOG_ENCODE で指定します。
    106         *
    107         * @param  event コンテキストイベント
    108         */
    109        @Override
    110        public void contextInitialized( final ServletContextEvent event ) {
    111                final ServletContext context = event.getServletContext();
    112
    113                final Map<String,String> param = SystemParameter.makeSystemParameter( context );
    114                HybsSystem.setInitialData( param );                     // 4.0.0 (2005/01/31)
    115
    116                // 4.3.4.1 (2008/12/08) ログの環境変数対応
    117//              LogWriter.init( HybsSystem.url2dir( System.getProperty( "SYS_LOG_URL" ,HybsSystem.sys( "SYS_LOG_URL" ) ) ) );
    118
    119                // 7.1.0.1 (2020/02/07) ログファイルのエンコードを SYS_LOG_ENCODE で指定します。
    120                final String LOG_DIR = HybsSystem.url2dir( System.getProperty( "SYS_LOG_URL" ,HybsSystem.sys( "SYS_LOG_URL" ) ) );
    121                final String LOG_ENC = System.getProperty( "SYS_LOG_ENCODE" ,HybsSystem.sys( "SYS_LOG_ENCODE" ) );
    122                LogWriter.init( LOG_DIR,LOG_ENC );
    123
    124                // CONTEXT_INITIAL_CALL_URL で登録されたURLを実行します。
    125                // 処理は、contextInitialized が終了してから実行する必要があります。
    126                new Thread( new InitialCallURL() ).start();
    127
    128                System.out.println( "-------" );
    129
    130                // 6.3.8.3 (2015/10/03) プログラムによるWebアプリケーションの拡張
    131        //      addRegistration( context );
    132
    133//              // https://support.oracle.com/knowledge/Middleware/1908414_1.html
    134//              // Tomcat 上でOracle JDBC Thin Driver が使用するスレッドがリークする (Doc ID 1908414.1)
    135//              final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
    136//              try {
    137//                      Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
    138//                      java.sql.DriverManager.getDrivers();
    139//                      Class.forName("oracle.jdbc.driver.OracleTimeoutThreadPerVM");
    140//              } catch (ClassNotFoundException e) {
    141//                      System.out.println( "OracleTimeoutThreadPerVM ClassNotFound" );
    142//                      /* noop */
    143//              } finally {
    144//                      Thread.currentThread().setContextClassLoader(contextClassLoader);
    145//              }
    146        }
    147
    148        /**
    149         *  ServletContextListener インターフェースの実装
    150         *
    151         * Webアプリケーションがシャットダウンされることを
    152         * リスナーに通知する。
    153         *
    154         * @og.rev 3.1.1.1 (2003/04/03) キャッシュクリアメソッドを新規追加。
    155         * @og.rev 3.3.3.3 (2003/08/06) HybsTimerTaskManager を終了時にキャンセルするロジックを追加。
    156         * @og.rev 3.5.2.1 (2003/10/27) リンクエラー対策：永続化セッション(SESSIONS.ser)からオブジェクトを削除しておく。
    157         * @og.rev 3.6.0.0 (2004/09/17) CalendarFactory.clear() を追加します。
    158         * @og.rev 4.0.0.0 (2005/01/31) コンテキスト名の取り方を変更します。
    159         * @og.rev 4.0.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
    160         * @og.rev 4.0.0.0 (2005/01/31) HybsTimerTaskManager は、Cleanable インターフェースによる初期化
    161         * @og.rev 4.1.0.0 (2007/12/27) GE12のクリア処理追加
    162         * @og.rev 4.3.0.0 (2008/07/18) soffice.binのタスクを削除する処理を追加
    163         * @og.rev 5.0.2.0 (2009/11/01) 再編成機能追加
    164         *
    165         * @param  event コンテキストイベント
    166         */
    167        @Override
    168        public void contextDestroyed( final ServletContextEvent event ) {
    169                final String name = HybsSystem.sys( "CONTEXT_NAME" );
    170                System.out.println( "Context Destroyed [" + name + "]  " + new Date() );
    171
    172                // 4.1.0.0 (2007/12/26) GE12からSystemParameterで設定したコンテキスト関係の情報
    173                SystemManager.clearGE12();
    174
    175                // 4.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
    176                SystemManager.allClear( true ) ;
    177
    178                // 4.3.0.0 (2008/07/18) soffice.binを全てkillします
    179        //      SystemManager.sofficeKill();
    180
    181                SystemManager.sessionDestroyed();               // 3.5.2.1 (2003/10/27)
    182
    183                SystemManager.deleteGUIAccessInfo();    // 5.0.2.0 (2009/11/01)
    184
    185                System.out.println( "-------" );
    186        }
    187
    188        /**
    189         *  ContainerListener インターフェースの実装
    190         *
    191         * セッション固定攻撃対策として、認証の前後でセッションIDが変更されるようになりました。
    192         * セッションIDの変更を検知したい場合は、ContainerListenerを実装する必要があります。
    193         *
    194         * ※ 使い方が分からないので、うまくイベントを拾えていません。
    195         *
    196         * @og.rev 6.3.9.0 (2015/11/06) 新規追加
    197         *
    198         * @param  event コンテナイベント
    199         */
    200        @Override
    201        public void containerEvent( final ContainerEvent event ) {
    202                System.out.println( "【ContainerEvent:" + event.getType() + " : " + event.toString() + "】" );
    203        }
    204
    205        /**
    206         *  ServletContextListener による、ServletやFilter の動的登録。
    207         *
    208         * プログラムによるWebアプリケーションの拡張として、Servlet 3.0 より
    209         * ServletやFilter を、ServletContextListenerのcontexInitializedメソッド から
    210         * 動的に設定できるようになりました。
    211         *
    212         * @og.rev 6.3.8.3 (2015/10/03) プログラムによるWebアプリケーションの拡張
    213         *
    214         * @param  context ServletContextオブジェクト
    215         */
    216        private void addRegistration( final ServletContext context ) {
    217
    218                // web.xml では、filter の定義が先だったので、気持ち、先に設定しておきます。
    219                // ******* Filter *******
    220
    221                // AccessStopFilter             (初期:false)
    222                final FilterRegistration frAS = context.addFilter( "AccessStopFilter", "org.opengion.hayabusa.filter.AccessStopFilter" );
    223                // frAS.setInitParameter( "startTime", "070000" );
    224                // frAS.setInitParameter( "stopTime" , "070000" );
    225                // frAS.setInitParameter( "filename" , "jsp/custom/stopFile.html" );
    226                frAS.addMappingForUrlPatterns( EnumSet.of(DispatcherType.REQUEST ), true, "/jsp/*" );
    227
    228                // GZIPFilter                   (初期:false)
    229                final FilterRegistration frGZ = context.addFilter( "GZIPFilter", "org.opengion.hayabusa.filter.GZIPFilter" );
    230                // frGZ.setInitParameter( "ipAddress", "192.168.,127.0.0.1" );
    231                // frGZ.setInitParameter( "debug"    , "false" );
    232                frGZ.addMappingForUrlPatterns( EnumSet.of(DispatcherType.REQUEST ), true, "/jsp/*" );
    233
    234                // FileFilter                   (初期:false)
    235                final FilterRegistration frFF = context.addFilter( "FileFilter", "org.opengion.hayabusa.filter.FileFilter" );
    236                // frFF.setInitParameter("saveDir", "filetemp/DIR/");
    237                frFF.addMappingForUrlPatterns( EnumSet.of(DispatcherType.REQUEST ), true, "/jsp/*" );
    238
    239                // URLCheckFilter               (初期:false)
    240                final FilterRegistration frUC = context.addFilter( "URLCheckFilter", "org.opengion.hayabusa.filter.URLCheckFilter" );
    241                // frUC.setInitParameter( "filename"  , "jsp/custom/refuseAccess.html" );
    242                // frUC.setInitParameter( "debug"     , "false" );
    243                // frUC.setInitParameter( "ignoreURL" , "" );
    244                frUC.addMappingForUrlPatterns( EnumSet.of(DispatcherType.REQUEST ), true, "/jsp/*" );
    245
    246                // URLHashFilter                (初期:true)
    247                final FilterRegistration frUH = context.addFilter( "URLHashFilter", "org.opengion.hayabusa.filter.URLHashFilter" );
    248                // frUH.setInitParameter( "filename", "jsp/custom/refuseAccess.html" );
    249                // frUH.setInitParameter( "initPage", "/jsp/index.jsp" );
    250                // frUH.setInitParameter( "debug"    , "false" );
    251                frUH.addMappingForUrlPatterns( EnumSet.of(DispatcherType.REQUEST ), true, "*.jsp" );
    252
    253                // ******* Servlet *******
    254
    255                // FileDownload
    256                final ServletRegistration srFD = context.addServlet( "fileDownload", "org.opengion.hayabusa.servlet.FileDownload" );
    257                srFD.addMapping( "/jsp/fileDownload" );
    258
    259                // HybsAdmin
    260                final ServletRegistration srAD = context.addServlet( "admin", "org.opengion.hayabusa.servlet.HybsAdmin" );
    261                srAD.addMapping( "/jsp/admin" );
    262
    263                // MakeImage
    264                final ServletRegistration srMI = context.addServlet( "makeImage", "org.opengion.hayabusa.servlet.MakeImage" );
    265                srMI.addMapping( "/jsp/makeImage" );
    266
    267                // RemoteControlServlet
    268                final ServletRegistration srRC = context.addServlet( "remoteControl", "org.opengion.hayabusa.servlet.RemoteControlServlet" );
    269                srRC.addMapping( "/servlet/remoteControl" );
    270        }
    271
    272        /**
    273         * CONTEXT_INITIAL_CALL_URL を起動する為のスレッド内部クラスです。
    274         *
    275         * HybsContextListener が正常終了しないと、Tomcatが起動したことになっていない為、
    276         * 通常のJSP処理が出来ません。
    277         * ここでは、Tomcat起動時に初期処理URL(CONTEXT_INITIAL_CALL_URL)をコールする為に、
    278         * 時間差を利用する為、スレッド化して実行させます。
    279         * このスレッドは、２秒間スリープ後に、初期処理URLを呼び出します。
    280         *
    281         * @og.rev 4.2.2.0 (2008/05/22) 初期URLの接続ユーザーをシステムリソースより取得
    282         * @og.rev 6.9.0.0 (2018/01/31) URLConnect 廃止、HttpConnect に置き換えます。
    283         * @og.rev 6.9.0.1 (2018/02/05) URL接続エラー時に、LOGだけではわかりにくいので、画面にも出します。
    284         * @og.rev 6.9.0.1 (2018/02/05) URLの値の取り出し時に、{&#064;SYS},{&#064;ENV} の文字列変換を行います。
    285         *
    286         * @og.group ログイン制御
    287         *
    288         * @version  4.0
    289         * @author   Kazuhiko Hasegawa
    290         * @since    JDK5.0,
    291         */
    292        private static final class InitialCallURL implements Runnable {
    293                /**
    294                 * スレッドの処理開始メソッド。
    295                 *
    296                 */
    297                public void run() {
    298                        try {
    299                                Thread.sleep( 2000 );
    300                        }
    301                        catch( final InterruptedException ex) {
    302                                LogWriter.log( "InterruptedException:" + ex.getMessage() );
    303                        }
    304
    305                        final String      name = HybsSystem.sys( "CONTEXT_NAME" );              // 6.9.0.0 (2018/01/31)
    306                        final HybsEntry[] urls = HybsSystem.sysEntry( "CONTEXT_INITIAL_CALL_URL" );
    307                        final String  userPass = HybsSystem.sys( "CONTEXT_INITIAL_CALL_USERPASS" );
    308
    309                        boolean isCall = false;
    310                        if( urls.length > 0 ) {
    311                                for( int i=0; i<urls.length; i++ ) {
    312//                                      final String url = urls[i].getValue();
    313                                        final String url = HybsSystem.changeParam( urls[i].getValue() );                // 6.9.0.1 (2018/02/05) 文字列変換
    314                                        if( url == null || url.isEmpty() ) { continue; }
    315        //                              final URLConnect conn = new URLConnect( url,userPass );
    316                                        final HttpConnect conn = new HttpConnect( url,userPass );                               // 6.9.0.0 (2018/01/31) URLConnect 廃止、HttpConnect に置き換えます。
    317                                        final String msg = "    [" + name + "] URL[" + i + "]:" + url ;                 // 6.9.0.1 (2018/02/05) 共通文字列
    318                                        try {
    319        //                                      conn.connect();
    320        //                                      final String msg = conn.getCode() + ":" + conn.getMessage() ;
    321                                                conn.readData();                                                                                                        // 6.9.0.0 (2018/01/31) 状態を確認する HttpHead は用意していない。GET で代用
    322        //                                      conn.disconnect();
    323//                                              System.out.println( "    [" + name + "] URL[" + i + "]:" + url );
    324        //                                      System.out.println( "           " + msg );
    325                                                System.out.println( msg );                                                                                      // 6.9.0.1 (2018/02/05)
    326                                                System.out.println( "           " + conn.getMessage() );                        // 6.9.0.0 (2018/01/31)
    327                                                isCall = true ;
    328                                        }
    329                                        catch( final IOException ex ) {
    330                                                // 6.9.0.1 (2018/02/05) URL接続エラー時に、LOGだけではわかりにくいので、画面にも出します。
    331//                                              LogWriter.log( "    [" + name + "] URL[" + i + "]:" + url );
    332//                                              LogWriter.log( "           " + ex.getMessage() );
    333
    334                                                final String errMsg = "           " + ex.getMessage();                          // 6.9.0.1 (2018/02/05)
    335                                                LogWriter.log( msg );
    336                                                LogWriter.log( errMsg );
    337                                                LogWriter.log( ex );
    338
    339                                                System.out.println( "    [CONTEXT_INITIAL_CALL_URL Error!]" );
    340                                                System.out.println( msg );
    341                                                System.out.println( errMsg );
    342                                        }
    343                                }
    344                        }
    345                        if( isCall ) {
    346//                              System.out.println( "  CONTEXT_INITIAL_CALL_URL" );
    347                                System.out.println( "    [" + name + "] CONTEXT_INITIAL_CALL_URL" );            // 6.9.0.0 (2018/01/31)
    348                                System.out.println( "-------" );
    349                        }
    350                }
    351        }
    352}