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 *     <listener>
058 *         <listener-class>
059 *             org.opengion.hayabusa.common.HybsContextListener
060 *         </listener-class>
061 *     </listener>
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         * このスレッドは、2秒間スリープ後に、初期処理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}