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