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