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.io.PrintWriter;
019import java.io.IOException;
020import java.io.UnsupportedEncodingException;
021import java.lang.reflect.Field;
022import java.lang.reflect.Modifier;
023import java.net.MalformedURLException;
024import java.net.URL;
025import java.sql.Connection;
026import java.sql.PreparedStatement;
027import java.sql.ResultSet;
028import java.sql.SQLException;
029import java.util.ArrayList;
030import java.util.Date;
031import java.util.Enumeration;
032import java.util.HashMap;
033import java.util.LinkedHashMap;
034import java.util.TreeMap;
035import java.util.List;
036import java.util.Locale;
037import java.util.Map;
038import java.util.Set;
039import java.util.Collections;                                                                                   // 6.4.3.2 (2016/02/19)
040import java.util.Calendar;                                                                                              // 6.9.7.0 (2018/05/14)
041
042import jakarta.servlet.ServletContext;
043import jakarta.servlet.FilterRegistration;                                                              // 6.9.3.1 (2018/04/02)
044import jakarta.servlet.ServletRegistration;                                                             // 6.9.3.1 (2018/04/02)
045
046import org.opengion.fukurou.db.ConnectionFactory;
047import org.opengion.fukurou.system.BuildNumber;                                                 // 6.4.2.0 (2016/01/29) hayabusa.common.BuildNumber → fukurou.system.BuildNumber に移動
048import org.opengion.fukurou.system.Closer;
049import org.opengion.fukurou.system.LogWriter;
050import org.opengion.fukurou.system.ThrowUtil;                                                   // 6.4.2.0 (2016/01/29)
051import org.opengion.fukurou.system.DateSet;                                                             // 6.9.7.0 (2018/05/14)
052import org.opengion.fukurou.util.FindClassFiles;
053import org.opengion.fukurou.util.StringUtil;
054import org.opengion.fukurou.xml.XMLFileLoader;                                                  // 6.0.0.0 (2014/04/11)
055import org.opengion.fukurou.system.HybsConst;                                                   // 7.2.3.1 (2020/04/17)
056import static org.opengion.fukurou.system.HybsConst.CR;                                 // 6.1.0.0 (2014/12/26)
057import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;              // 6.1.0.0 (2014/12/26) refactoring
058import static org.opengion.fukurou.system.HybsConst.DB_FETCH_SIZE;              // 6.9.4.1 (2018/04/09)
059import org.opengion.fukurou.fileexec.MainProcess;                                               // 7.2.5.3 (2020/06/16)
060
061/**
062 * ログインしたサーブレットコンテキストに対応したシステムパラメータデータを取得するクラスです。
063 *
064 * システムパラメータデータ(GE12)は、パラメータ(PARAM_ID)に対して、各種設定値(PARAM)を
065 * 持っています。
066 * 従来は、resource.システムパラメータ の一般設定用の システムパラメータ ファイルと
067 * エンジン内部で持っている org/hsgw/hayabusa/resource/properties の
068 * システムパラメータ ファイルにより維持されていましたが、システムパラメータ
069 * 定義テーブル(GE12)と、commom/SystemData.java クラスによる管理に変更されました。
070 *
071 * システムパラメータは、DBへのアクセスを決定するため、初期設定値を定義する必要があります。
072 * これは、アプリケーション・ディスクリプタ(WEB-INF/web.xml)に、context-param として、
073 * キーと値のセットで、初期アクセス用の情報を渡します。
074 * システムパラメータ定義テーブル(GE12)には、SYSTEM_IDとして、通常のシステムIDと、
075 * エンジンパラメータがあります。エンジンパラメータは、SYSTEM_ID='**'として、登録
076 * されています。
077 *
078 * <table class="plain">
079 *   <caption>システムパラメータの説明</caption>
080 *   <tr><th>種類       </th><th>SYSTEM_ID</th><th>作成区分</th><th>説明</th></tr>
081 *   <tr><td>エンジン共通    </td><td>**             </td><td>0:エンジン</td><td>エンジン共通で定義しているパラメータ                   </td></tr>
082 *   <tr><td>エンジン個別    </td><td>個別     </td><td>0:エンジン</td><td>システム毎にエンジンが登録しているパラメータ               </td></tr>
083 *   <tr><td>システム共通     </td><td>**             </td><td>1:システム </td><td>システム毎にエンジンが登録しているパラメータ               </td></tr>
084 *   <tr><td>システム個別     </td><td>個別     </td><td>1:システム </td><td>システム毎に各自が独自に登録しているパラメータ       </td></tr>
085 * </table>
086 *
087 * <table class="plain">
088 *   <caption>アプリケーション・ディスクリプタ(WEB-INF/web.xml)設定情報</caption>
089 *   <tr><th>パラメータ             </th><th>設定値例                           </th><th>解説                                     </th></tr>
090 *   <tr><td>SYSTEM_ID  </td><td>GE                                             </td><td>このアプリケーションのシステムID     </td></tr>
091 *   <tr><td>TOMCAT_PORT</td><td>8823                                   </td><td>Tomcat起動時ポート番号        </td></tr>
092 *   <tr><td>LOG_FILE   </td><td>log/log_$(yyyyMMdd).txt</td><td>JSPアクセスログ出力先          </td></tr>
093 * </table>
094 *
095 * ※ 5.6.7.0 (2013/07/27)
096 *    InitFileLoader により、特定のクラスパス内の 拡張XDK 形式の xml ファイル を処理します。
097 *    クラスパスが、"/resource" 以下のすべての xml ファイルは、DBIDが RESOURCE の接続先に対して処理されます。
098 *    クラスパスが、"/xml" 以下のすべての xml ファイルは、DBIDが DEFAULT の接続先に対して処理されます。
099 *    各クラスパス以下のファイルは、実フォルダでも、jar形式に圧縮された形式でも処理されます。
100 *
101 * ※ 6.0.0.0 (2014/04/11)
102 *    InitFileLoader が廃止になり、代わりに、XMLFileLoader を使用します。処理自体は、ほぼ同様です。
103 *
104 * @og.rev 4.0.0.0 (2005/01/31) 新規作成
105 * @og.rev 4.0.0.0 (2007/10/26) loadDBResourceのコネクションをFactoryから取るように変更
106 * @og.group 初期化
107 *
108 * @version     4.0
109 * @author      Kazuhiko Hasegawa
110 * @since       JDK5.0,
111 */
112public final class SystemParameter {
113
114        /** plugin クラスの取得用クラスパス指定      {@value}        */
115        public static final String PLUGIN = "org/opengion/plugin";
116
117        // 4.0.0.0 (2007/10/05) CONTXT_PATH に、DEFAULT '**' NOT NULL 制約を付ける。
118        /** システム共通/個別パラメータ(SYSTEM_ID in ('**',?) and KBSAKU &gt; '0')の一括読込のクエリー        {@value}        */
119        public static final String QUERY = "SELECT PARAM_ID,PARAM,FGCRYPT"
120                                                                        + " FROM GE12 WHERE SYSTEM_ID IN (?,'**')"
121                                                                        + " AND CONTXT_PATH IN (?,'**')"
122                                                                        + " AND FGJ='1' AND KBSAKU > '0'"
123                                                                        + " ORDER BY SYSTEM_ID,CONTXT_PATH,FGJ,KBSAKU,SEQNO" ;
124
125        /** システム共通/個別パラメータ(SYSTEM_ID in ('**',?) and KBSAKU &gt; '0')の一括登録のクエリー        {@value}        */
126        public static final String INS_SYS = "INSERT INTO GE12"
127//                                                                      + " ( SYSTEM_ID,CONTXT_PATH,PARAM_ID,SEQNO,PARAM,TITLE,CONTENTS,PARAM_LVL,FGJ,KBSAKU )"
128                                                                        + " ( SYSTEM_ID,CONTXT_PATH,PARAM_ID,SEQNO,PARAM,TITLE,CONTENTS,PARAM_LVL,FGJ,KBSAKU,DYSET )"   // 6.9.7.0 (2018/05/14)
129                                                                        + " SELECT"
130//                                                                      + " ?,?,?,?,?,TITLE,CONTENTS,PARAM_LVL,'1','0'"
131                                                                        + " ?,?,?,?,?,TITLE,CONTENTS,PARAM_LVL,'1','0',?"                                                                                               // 6.9.7.0 (2018/05/14)
132                                                                        + " FROM GE12 WHERE SYSTEM_ID='**' AND FGJ='1' AND KBSAKU='0' AND PARAM_ID=?" ;
133
134//      /** エンジン個別(SYSTEM_ID='個別' KBSAKU='0' CONTXT_PATH='自身')パラメータの一括削除のクエリー {@value}        */
135//      public static final String DEL_SYS = "DELETE FROM GE12 WHERE SYSTEM_ID=? AND KBSAKU='0' AND CONTXT_PATH=?";
136
137        /** エンジン個別(SYSTEM_ID='個別' KBSAKU='0' CONTXT_PATH='自身')パラメータの一括削除と、過去情報の削除クエリー {@value}        */
138        public static final String DEL_SYS = "DELETE FROM GE12 WHERE ( SYSTEM_ID=? AND KBSAKU='0' AND CONTXT_PATH=? )"                                  // 6.9.7.0 (2018/05/14)
139                                                                        + " OR ( SYSTEM_ID != '**' AND PARAM_LVL='9' AND ( DYSET < ? OR DYSET IS NULL ) )" ;                    // 過去のデータを考慮(DYSET is null)
140
141        /** 6.9.7.0 (2018/05/14) DYSET フォーマット   {@value}        */
142        public static final String DYSET_FORMAT = "yyyyMMddHHmmss" ;                    // 6.9.7.0 (2018/05/14)
143
144//      /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ       {@value}        */
145//      private static final int DB_FETCH_SIZE = 1001 ;                                                 // HybsSystem に設定する前なので、HybsSystem.sysInt では取得できない。
146
147        /** システムパラメータ構築中のエラーをセットしていきます。 */
148        private static final List<String> ERR_MSG_LIST = new ArrayList<>();             // 6.4.1.1 (2016/01/16) errMsgList → ERR_MSG_LIST refactoring
149
150        /**
151         * デフォルトコンストラクターをprivateにして、
152         * オブジェクトの生成をさせないようにする。
153         *
154         */
155        private SystemParameter() {}
156
157        /**
158         * コンテキスト毎に システムパラメータオブジェクトを作成します。
159         * このクラスのスタートポイントメソッドになります。
160         *
161         * @og.rev 4.1.0.1 (2008/01/23) ログ出力先の変更(全てLogWriter経由で出力)
162         * @og.rev 5.5.4.4 (2012/07/20) LogWriter.log 追加
163         * @og.rev 5.5.4.4 (2012/07/20) SQLException は、catch しているので、loadDBResource からは、throws されない。
164         * @og.rev 5.7.2.0 (2014/01/10) Throwable の情報をもう少し詳細に出します。
165         * @og.rev 6.4.3.2 (2016/02/19) engParamとsysParamを初期設定して、同期化しておく。
166         * @og.rev 6.4.7.1 (2016/06/17) セキュリティの関連で、ログの詳細を出していませんでしたが、出すように変更します。
167         * @og.rev 6.8.6.0 (2018/01/19) ImageIO.write で、Java9で、NumberFormatException が出てしまう(暫定)対策。
168         * @og.rev 7.2.5.3 (2020/06/16) MainProcessは、SystemParameterへ移動
169         * @og.rev 7.3.2.3 (2021/04/09) システム定数のICON_DIRやIMAGE_DIRを使用します。
170         *
171         * @param       context Servletコンテキスト
172         *
173         * @return      システムパラメータのマップ
174         */
175        public static Map<String,String> makeSystemParameter( final ServletContext context ) {
176                ERR_MSG_LIST.clear() ;  // 呼び出し都度、エラーリストをクリアします。
177
178                // 6.4.3.2 (2016/02/19)
179                final Map<String,String> engParam = new LinkedHashMap<>();      // 最終的にマージして返す。
180                final Map<String,String> sysParam = new LinkedHashMap<>();      // DB書き戻し等あるので、設定中は分けておく。
181
182                try {
183                        // 6.8.6.0 (2018/01/19) ImageIO.write (暫定)対策
184                        // ※ ImageIO.getReaderMIMETypes(); での Java 9 has java.specification.version == 9 で、
185                        // Caused by: java.lang.NumberFormatException: For input string: "" が発生する対応
186                        // https://github.com/jai-imageio/jai-imageio-core/issues/24
187                        final String javaSpecVer = System.getProperty( "java.specification.version" );
188                        if( !javaSpecVer.startsWith( "1." ) ) {
189                                System.setProperty( "java.specification.version" , "1." + javaSpecVer );        // "java.specification.version" , "9" の場合、"1.9" に無理やり変更します。
190                        }
191
192                        final String contextName = getContextName( context );
193
194                        System.out.println( "Context Initialized [" + contextName + "] " + new Date() );
195                        System.out.print( "  Version [" + BuildNumber.VERSION_NO + " " );
196                        System.out.print( BuildNumber.BUILD_TYPE );
197                        System.out.println( "]" );
198
199                        // システムデータクラスより、エンジンパラメータ情報を初期設定します。
200                        // エンジンパラメータは、SystemData クラスの public static メンバーです。
201                        loadParameter( engParam , SystemData.class );                           // 6.4.3.2 (2016/02/19)
202
203                        // コンテキストより取得できるシステムパラメータ情報を取得します。
204                        // web.xml で設定したパラメータを取得します。
205                        // SYSTEM_ID,DB_DRIVER,DB_URL などは、loadDBResource で使用します。
206                        loadInitialParameter( sysParam , context , contextName );       // 6.4.3.2 (2016/02/19)
207
208                        // システム個別に設定される、エンジン起動時情報を初期設定します。
209                        // エンジン起動時情報は、BuildNumber クラスの public static メンバーです。
210                        loadParameter( sysParam , BuildNumber.class );                          // 6.4.3.2 (2016/02/19)
211                        loadParameter( sysParam , PLUGIN );
212
213                        // GE12 データベースより読み取ります。
214                        // 引数のMapに読み込んだ値を追加した Map を返します。
215                        // つまり、システムパラメータ情報の上書きを行います。
216                        // 5.5.4.4 (2012/07/20) SQLException は、catch しているので、loadDBResource からは、throws されない。
217        //              try {
218                                loadDBResource( sysParam );                                                             // 6.4.3.2 (2016/02/19)
219        //              }
220        //              catch( final SQLException ex ) {
221        //              final String errMsg = "DB終了(close)処理を実行できませんでした。" + CR
222        //                                              + ex.getMessage() + ":" + ex.getSQLState() ;
223        //                      LogWriter.log( ex );                                    // 5.5.4.4 (2012/07/20) LogWriter.log 追加
224        //                      ERR_MSG_LIST.add( errMsg );
225        //              }
226
227                        // 7.2.5.3 (2020/06/16) MainProcessは、SystemParameterへ移動
228                        // 7.2.5.0 (2020/06/01) org.opengion.fukurou.fileexec.MainProcess処理
229                        // InitialCallURL() の起動が一番最後なので、その前に入れます。
230                        if( "GE".equalsIgnoreCase( contextName ) ) {
231                                if( "true".equalsIgnoreCase( sysParam.get( "USE_FILEEXEC" ) ) ) {
232                                        MainProcess.start();
233                                }
234                                else {
235                                        MainProcess.shutdown( false );
236                                }
237                        }
238
239                        // 7.3.2.3 (2021/04/09) システム定数のICON_DIRやIMAGE_DIRを使用します。
240                        // GE12の初期値のSQLは、KBSAKU > '0' しか取得しないので、初期値を、engParam から取ってくる。
241                        final String JSP                = sysParam.get( "JSP" );
242                        final String ICON_DIR   = StringUtil.nval( sysParam.get( "ICON_DIR"  ),engParam.get( "ICON_DIR"  ) );
243                        final String IMAGE_DIR  = StringUtil.nval( sysParam.get( "IMAGE_DIR" ),engParam.get( "IMAGE_DIR" ) );
244                        sysParam.put( "JSP_ICON",JSP+"/"+ICON_DIR  );
245                        sysParam.put( "JSP_IMG" ,JSP+"/"+IMAGE_DIR );
246                }
247                catch( final Throwable th ) {                                   // 3.6.1.0 (2005/01/05)
248                        LogWriter.log( th );                                            // 5.5.4.4 (2012/07/20) LogWriter.log 追加
249                        // 5.7.2.0 (2014/01/10) Throwable の情報をもう少し詳細に出します。
250                        final String errMsg = "処理を実行できませんでした。"  + CR ;
251        //                                      + th.getMessage()                                               + CR
252        //                                      + StringUtil.ogStackTrace( th ) ;
253        //              ERR_MSG_LIST.add( errMsg );
254        //              final String errMsg = "処理を実行できませんでした。"  + CR ;                  // 6.4.7.1 (2016/06/17)
255                        ERR_MSG_LIST.add( ThrowUtil.ogStackTrace( errMsg,th ) );                                // 6.4.2.0 (2016/01/29)
256                }
257                finally {
258                        // 初期値のエンジンパラメータに個別のシステムパラメータを追加設定します。
259                        // つまり、エンジンパラメータ情報に上書きを行います。
260                        // 6.3.9.1 (2015/11/27) engParam が null になることは無い(findbugs)。
261                                engParam.putAll( sysParam );
262
263                        final int errCnt = ERR_MSG_LIST.size();
264                        if( errCnt > 0 ) {
265                                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
266                                        .append( "【システムパラメータの初期化に失敗しました。】" )
267                                        .append( CR )
268                                        .append( "Tomcat の設定状況をご確認ください。" )
269                                        .append( CR )
270                                        .append( "========================================" )
271                                        .append( CR );
272
273                                for( int i=0; i<errCnt; i++ ) {
274                                        buf.append( ERR_MSG_LIST.get(i) )
275                                                .append( CR )
276                                                .append( "----------------------------------------" )
277                                                .append( CR );
278                                }
279                                System.out.println( buf );
280                                engParam.put( HybsSystem.LOCAL_CONTX_ERR_KEY,buf.toString() );
281                        }
282                }
283                return Collections.synchronizedMap( engParam ) ;                // 6.4.3.2 (2016/02/19) 同期化しておく。
284        }
285
286        /**
287         * コンテキストより、アプリケーション設定情報を取得します。
288         * 初期値は、アプリケーション・ディスクリプタ(WEB-INF/web.xml)に
289         * context-param として、キーと値のセットで、初期アクセス用の情報を渡します。
290         * データベースへの接続は、WEB-INF の DBConfig.xml で設定された情報を使用します。
291         *
292         * ここでは、各コンテキスト毎の内部情報を取得します。その中には、
293         * BuildNumber クラスで定義されている各種フィールド属性も含まれます。
294         *
295         * REAL_PATH      : アドレス(/)に対する、実ディレクトリパス
296         * CONTEXT_NAME   : アクセス先の仮想フォルダ名(URLのコンテキスト名)
297         * JSP            : アクセス先のJSPフォルダ名(/URLのコンテキスト名/jsp)
298         * SYS_LOG_URL    : jsp以下のログファイル名                                                                              // 7.1.0.0 (2020/01/20) jsp以下のログファイル名
299         * SYSTEM_ID      : web.xml で指定する、SYSTEM_ID の設定値
300         * TOMCAT_PORT    : web.xml で指定する、Tomcat起動時ポート番号(8823)
301         * LOG_FILE       : web.xml で指定する、JSPアクセスログ出力先(log/log_$(yyyyMMdd).txt)
302         * SERVLET_INFO   : サーブレット情報 [例: Apache Tomcat/5.5.9 ]
303         * TOMCAT_WORK    : Tomcatワークの位置 [例: H:\java\tomcat5.5.17\work\Catalina\localhost\ver4 ]
304         * TOMCAT_HOME    : Tomcat環境の位置 [例: H:\java\tomcat5.5.17 ]
305         * LOGS_DIR       : Tomcatのログフォルダ                                                                             // 7.1.0.0 (2020/01/20) Tomcatのログフォルダ
306         * JAVA_HOME      : Java実行環境の位置 [例: H:\java\jdk150\jre ]
307         * HOST_NAME      : ホストの名前
308         * HOST_ADRS      : ホストのアドレス
309         * SERVER_INFO    : サーバー情報 [例: HN50G5 ( 200.1.50.165 ) ]
310         * ENGINE_INFO    : バージョン番号 [例: 4.3.6.6 ]
311         * RESOURCE_DBID  : "RESOURCE" 固定値を設定。WEB-INF/web.xml で指定しても無効です。
312         * OFFICE_HOME    : オフィースのHOME                                                                                          // 7.1.0.0 (2020/01/20) オフィースのHOME
313         * EXT_DIR        : 拡張jarフォルダ                                                                                  // 7.1.0.0 (2020/01/20) 拡張jarフォルダ
314         * IS_SERVICE     : サービス起動かどうか [サービス起動時はtrue]                                 // 7.1.0.0 (2020/01/20) サービス起動
315         *
316         * @og.rev 4.1.0.0 (2007/12/27) web.xmlからTOMCAT_PORTを読む処理を追加
317         * @og.rev 4.2.0.0 (2008/02/18) TOMCAT_PORTを環境変数から取得するよう変更
318         * @og.rev 4.2.0.0 (2008/02/20) web.xmlでSYSTEM_IDが空白の場合に大文字コンテキスト名が設定されるよう変更
319         * @og.rev 4.3.6.6 (2009/05/15) コンテキスト単位にエンジンバージョン情報を持つ(バージョンアップ判定用)
320         * @og.rev 5.6.7.1 (2013/08/09) RESOURCE_DBID の値に、"RESOURCE" を設定しておきます。
321         * @og.rev 5.6.7.3 (2013/08/23) TOMCAT_HOME を追加
322         * @og.rev 5.7.3.2 (2014/02/28) Tomcat8 対応。getRealPath( "/" ) の互換性のための修正。
323         * @og.rev 6.2.4.1 (2015/05/22) REAL_PATH 対応。realPath は、HybsSystem経由で、取得する。
324         * @og.rev 6.4.3.2 (2016/02/19) returnをやめて、引数のMapに直接値を設定します。
325         * @og.rev 6.9.0.1 (2018/02/05) RequestParam で設定される値を、できるだけ構築しておきます。
326         * @og.rev 6.9.3.1 (2018/04/02) web.xml で定義されている filter、servlet のキー名称を取得し、あれば、true を設定します。
327         * @og.rev 7.1.0.0 (2020/01/20) OFFICE_HOME,EXT_DIR,IS_SERVICE 環境変数の追加
328         * @og.rev 7.2.3.1 (2020/04/17) System.getenv → HybsConst.getenv 変更(サービス化対応)
329         * @og.rev 8.4.0.0 (2022/12/23) HybsConst.getenv の 初期値使用
330         *
331         * @param       map                     読み書きするMapオブジェクト
332         * @param       context         Servletコンテキスト
333         * @param       contextName     コンテキスト名
334         */
335        private static void loadInitialParameter( final Map<String,String> map,final ServletContext context,final String contextName ) {
336                // コンテキストの初期化パラメータ他の情報を登録しておきます。
337                final Enumeration<?> enume = context.getInitParameterNames() ;                  // 4.3.3.6 (2008/11/15) Generics警告対応
338                while( enume.hasMoreElements() ) {
339                        final String key = (String)enume.nextElement();
340                        String val = context.getInitParameter( key );
341                        if( val != null && val.isEmpty() ) { val = null; }
342                        map.put( key,val );
343                }
344
345                // SYSTEM_IDがnullの場合は大文字のコンテキスト名を設定
346                if( map.get( "SYSTEM_ID" ) == null ){ // 4.2.0.0 (2008/02/20)
347                        map.put( "SYSTEM_ID", contextName.toUpperCase( Locale.JAPAN ) );
348                }
349
350                // 6.2.4.1 (2015/05/22) REAL_PATH 対応。realPath は、HybsSystem経由で、取得する。
351                final String REAL_PATH = context.getRealPath( "" ) ;                                    // 7.1.0.0 (2020/01/20)
352//              HybsSystem.setRealPath( context.getRealPath( "" ) );
353                HybsSystem.setRealPath( REAL_PATH );                                                                    // 7.1.0.0 (2020/01/20)
354
355                // 各種システム情報を登録しておきます。
356//              map.put( "REAL_PATH"    ,HybsSystem.getRealPath() );                                    // 6.2.4.1 (2015/05/22)
357                map.put( "REAL_PATH"    ,REAL_PATH );                                                                   // 6.2.4.1 (2015/05/22) 7.1.0.0 (2020/01/20)
358                map.put( "CONTEXT_NAME" ,contextName );
359                map.put( "JSP"                  ,"/" + contextName + "/jsp" );
360//              map.put( "SYS_LOG_URL"  ,REAL_PATH + System.getenv( "SYS_LOG_URL" ) );  // 7.1.0.0 (2020/01/20) jsp以下のログファイル名
361
362                map.put( "SERVLET_INFO" ,context.getServerInfo() );
363                map.put( "TOMCAT_WORK"  ,String.valueOf( context.getAttribute( "jakarta.servlet.context.tempdir" ) ) );
364
365                // 7.1.0.0 (2020/01/20) TOMCAT_HOME を先に取得しておく。
366                final String TOMCAT_HOME = System.getProperty( "catalina.home" );
367//              map.put( "TOMCAT_HOME"  ,System.getProperty( "catalina.home" ) );                                               // 5.6.7.3 (2013/08/23)
368                map.put( "TOMCAT_HOME"  ,TOMCAT_HOME );                                                                                                 // 7.1.0.0 (2020/01/20) TomcatのHOMEフォルダ
369                map.put( "TOMCAT_LOGS"  ,TOMCAT_HOME + "/logs" );                                                                               // 7.1.0.0 (2020/01/20) Tomcatのログフォルダ
370//              map.put( "LOGS_DIR"             ,System.getProperty( "logsDir" ) );                                                             // 7.1.0.0 (2020/01/20) Tomcatのログフォルダ(コンテキスト単位)
371//              map.put( "SERVICE_NAME" ,StringUtil.nval( System.getenv( "SERVICE_NAME" ),"" ) );               // 7.1.0.0 (2020/01/20) サービス起動時のサービス名
372//              map.put( "SERVICE_NAME" ,StringUtil.nval( HybsConst.getenv( "SERVICE_NAME" ),"" ) );    // 7.2.3.1 (2020/04/17) サービス起動時のサービス名
373                map.put( "SERVICE_NAME" ,HybsConst.getenv( "SERVICE_NAME","" ) )                                ;               // 8.4.0.0 (2022/12/23) サービス起動時のサービス名 getenvの初期値を使用
374
375                map.put( "JAVA_HOME"    ,System.getProperty( "java.home" ) );
376
377                map.put( "HOST_NAME"    ,HybsSystem.HOST_NAME );
378                map.put( "HOST_ADRS"    ,HybsSystem.HOST_ADRS );
379                map.put( "SERVER_INFO"  ,HybsSystem.HOST_NAME + " ( " + HybsSystem.HOST_ADRS + " )" );
380                map.put( "ENGINE_INFO"  ,BuildNumber.ENGINE_INFO );
381                // 5.6.7.1 (2013/08/09) RESOURCE_DBID の値に、"RESOURCE" を設定しておきます。
382                map.put( "RESOURCE_DBID", "RESOURCE" );
383
384                // 7.1.0.0 (2020/01/20) OFFICE_HOME,EXT_DIR 環境変数の追加
385//              map.put( "OFFICE_HOME"  ,System.getenv( "OFFICE_HOME" ) );                              // 7.1.0.0 (2020/01/20) オフィースのHOME
386                map.put( "OFFICE_HOME"  ,HybsConst.getenv( "OFFICE_HOME" ) );                   // 7.2.3.1 (2020/04/17) オフィースのHOME
387//              map.put( "EXT_DIR"              ,System.getenv( "EXT_DIR" ) );                                  // 7.1.0.0 (2020/01/20) 拡張jarフォルダ
388                map.put( "EXT_DIR"              ,HybsConst.getenv( "EXT_DIR" ) );                               // 7.2.3.1 (2020/04/17) 拡張jarフォルダ
389
390                // 7.1.0.0 (2020/01/20) バッチ起動の場合は、sun.java.command = "org.apache.catalina.startup.Bootstrap start" , サービス起動時は、未設定
391                final boolean IS_SERVICE = null == System.getProperty( "sun.java.command" );
392                map.put( "IS_SERVICE"   , String.valueOf( IS_SERVICE ) );                               // 7.1.0.0 (2020/01/20) サービスなら、true
393
394                // 6.3.9.1 (2015/11/27) final化にともない、ロジック整理
395//              final String TOMCAT_PORT = StringUtil.nval( System.getenv( "CONNECTOR_PORT" ) , map.get( "TOMCAT_PORT" ) );
396//              final String TOMCAT_PORT = StringUtil.nval( HybsConst.getenv( "CONNECTOR_PORT" ) , map.get( "TOMCAT_PORT" ) );  // 7.2.3.1 (2020/04/17)
397                final String TOMCAT_PORT = HybsConst.getenv( "CONNECTOR_PORT" , map.get( "TOMCAT_PORT" ) );     // 8.4.0.0 (2022/12/23) getenvの初期値を使用
398
399                // 6.3.9.1 (2015/11/27) final化にともない、ロジック整理
400                final String HOST_URL = TOMCAT_PORT == null || TOMCAT_PORT.isEmpty()
401                                                                        ? "**" : HybsSystem.HOST_NAME + ":" + TOMCAT_PORT + "/" + contextName + "/";
402                map.put( "HOST_URL", HOST_URL );
403
404                // 6.9.0.1 (2018/02/05) RequestParam で設定される値を、できるだけ構築しておきます。
405                map.put( "SERVER_NAME"  , "localhost" );                                                // HybsSystem.HOST_NAME でも良いかも。
406                map.put( "SERVER_URL"   , "http://localhost:" + TOMCAT_PORT + "/" );
407                map.put( "CONTEXT_URL"  , "http://localhost:" + TOMCAT_PORT + "/" + contextName + "/" );
408
409                // 6.9.3.1 (2018/04/02) web.xml で定義されている filter、servlet のキー名称を取得し、あれば、true を設定します。
410                // キーワードは、USE_(大文字のフィルター名) です。
411                final Map<String,? extends FilterRegistration> filterMap = context.getFilterRegistrations();
412                for( final String fkey : filterMap.keySet() ) {
413                        map.put( "USE_" + fkey.toUpperCase( Locale.JAPAN ) , "true" );
414                }
415
416                // 6.9.3.1 (2018/04/02) web.xml で定義されている filter、servlet のキー名称を取得し、あれば、true を設定します。
417                // キーワードは、USE_(大文字のフィルター名) です。
418                final Map<String,? extends ServletRegistration> servletMap = context.getServletRegistrations();
419                for( final String skey : servletMap.keySet() ) {
420                        map.put( "USE_" + skey.toUpperCase( Locale.JAPAN ) , "true" );
421                }
422
423                System.out.println( "    Load Initial Parameter [" + map.size() + "] finished." );
424        }
425
426        /**
427         * アプリケーション個別に設定しているリソースDB(GE12)を取得します。
428         *
429         * データベースへの接続は、WEB-INF の DBConfig.xml で設定された情報を元に、
430         * org.opengion.fukurou.db.ConnectionFactory で接続先を取得します。
431         * ここでは、web.xml で定義された各アプリケーション個別のパラメ―タを取得します。
432         * SYSTEM_ID(必須) です。
433         *
434         * @og.rev 4.0.0.0 (2007/10/10) 接続先情報の管理見直し(コンテキスト初期設定)
435         * @og.rev 4.0.0.0 (2007/10/26) コネクションをファクトリーから取ってくるように変更
436         * @og.rev 4.3.6.5 (2009/05/08) dataパス内のXMLファイルも読み取るようにする
437         * @og.rev 4.3.6.6 (2009/05/15) ↑を廃止。自動インストール対応。
438         * @og.rev 5.1.2.0 (2010/01/01) connection.setAutoCommit は、ConnectionFactory で設定済みなので、コメントアウト
439         * @og.rev 5.1.9.0 (2010/08/01) 自動インストールの設定見直し(画面からのインストール対応)
440         * @og.rev 5.5.4.4 (2012/07/20) SQLException は、catch しているので、このメソッドからは、throws されない。
441         * @og.rev 5.5.4.5 (2012/07/27) 初期起動時のDB接続先は、RESOURCE_DBID とする。
442         * @og.rev 5.6.6.1 (2013/07/12) xml パス内のXMLファイルがあれば、DB登録します。
443         * @og.rev 5.6.7.0 (2013/07/27) InitFileLoader で、resource以下は、DBID=RESOURCE xml以下は、DBID=DEFAULT に登録します。
444         * @og.rev 5.6.7.3 (2013/08/23) DBID=RESOURCE 漏れ
445         * @og.rev 5.7.2.0 (2014/01/10) RuntimeException は、catch しないようにします。
446         * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
447         * @og.rev 6.4.3.2 (2016/02/19) returnをやめて、引数のMapに直接値を設定します。
448         * @og.rev 6.4.7.1 (2016/06/17) セキュリティの関連で、ログの詳細を出していませんでしたが、出すように変更します。
449         * @og.rev 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズを設定。
450         * @og.rev 8.5.0.0 (2023/04/21) 対象外の resource を読込んでいた為、判定条件を変更
451         *
452         * @param       sysParam        入力システムパラメータマップ
453         */
454        private static void loadDBResource( final Map<String,String> sysParam ) {
455                final String SYSTEM_ID          = sysParam.get( "SYSTEM_ID" );
456
457                // 必須項目チェックを行います。SYSTEM_IDは必須です。
458                // これは、web.xml で定義が必要です。
459                // 4.0.0.0 (2007/10/23)接続情報XML化につきDB_URLチェックを削除
460                if( SYSTEM_ID == null || SYSTEM_ID.isEmpty() ) {
461                        final String errMsg = "システムパラメータの必須項目(SYSTEM_ID,DB_URL)が null です。" + CR
462                                                        + "SYSTEM_ID=[" + SYSTEM_ID + "] " + CR
463                                                        + "Versino=[" + BuildNumber.VERSION_NO + "] " + CR ;
464                        ERR_MSG_LIST.add( errMsg );
465                        return ;                                                                                // 6.4.3.2 (2016/02/19)
466                }
467
468                Connection      defConn                 = null;                                 // 5.6.7.0 (2013/07/27) DBID=DEFAULT  のコネクション
469                Connection      rscConn                 = null;                                 // 5.6.7.0 (2013/07/27) DBID=RESOURCE のコネクション
470                boolean         errFlag                 = true;
471                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
472                final String CONTEXT_NAME       = sysParam.get( "CONTEXT_NAME" );       // コンテキスト別システムリソース
473                final String HOST_URL           = sysParam.get( "HOST_URL" );           // 4.1.0.0 (2007/12/21) TOMCATへのアクセス用
474                final String RESOURCE_DBID      = sysParam.get( "RESOURCE_DBID" );      // 5.5.4.5 (2012/07/27) 初期起動時のDB接続先
475                try {
476                        // 4.0.0.0(2007/10/25)ConnectionをConnectionFactory経由で取得するように変更する。
477                        // コンテキスト名で接続しにいく。ApplicationInfoは使わないのでnull
478                        ConnectionFactory.init( CONTEXT_NAME, null );   // ConnectionFactoryの初期化
479
480                        defConn = ConnectionFactory.connection( null, null );                   // 5.6.7.0 (2013/07/27) DBID=DEFAULT のコネクション
481                        rscConn = ConnectionFactory.connection( RESOURCE_DBID, null );  // 5.6.7.0 (2013/07/27) DBID=RESOURCE のコネクション
482
483                        // 4.3.6.6 (2009/05/15)
484                        // 5.1.9.0 (2010/08/01) 自動インストールの設定見直し(画面からのインストール対応)
485                        final SystemInstaller installer = new SystemInstaller( defConn , rscConn , new PrintWriter( System.out, true ) );
486                        installer.autoInsUpd( SYSTEM_ID, CONTEXT_NAME, HOST_URL );
487
488                        // resource パス内のXMLファイルがあれば、先にDB登録します。(DBID=RESOURCE)
489                        // 6.0.0.0 (2014/04/11) XMLFileLoader に変更。
490                        // 7.0.1.4 (2018/11/26) XMLFileLoader をfinal宣言(どうせ、new してるので使い回しを止める。)
491//                      XMLFileLoader loader = new XMLFileLoader( rscConn,true );                       // リソースコネクションとuseTimeStamp=true 指定
492//                      loader.loadClassPathFiles( "resource" ) ;
493                        final XMLFileLoader rscLoad = new XMLFileLoader( rscConn,true );        // リソースコネクションとuseTimeStamp=true 指定
494//                      rscLoad.loadClassPathFiles( "resource" ) ;
495                        // 8.5.0.0 (2023/04/21) C:/opengionVX/apps/LibreOfficeX.X.X/program/resource を対象外にする
496                        rscLoad.loadClassPathFiles( "resource", "webapps" ) ;
497
498                        // 5.6.6.1 (2013/07/12) xml パス内のXMLファイルがあれば、DB登録します。
499                        // 6.0.0.0 (2014/04/11) XMLFileLoader に変更。
500                        // 7.0.1.4 (2018/11/26) XMLFileLoader をfinal宣言(どうせ、new してるので使い回しを止める。)
501//                      loader = new XMLFileLoader( defConn,true );                                                     // デフォルトコネクションとuseTimeStamp=true 指定
502//                      loader.loadClassPathFiles( "xml" ) ;
503                        final XMLFileLoader xmlLoad = new XMLFileLoader( defConn,true );        // デフォルトコネクションとuseTimeStamp=true 指定
504                        xmlLoad.loadClassPathFiles( "xml" ) ;
505
506                        // コンテキスト単位のシステムパラメータを GE12 に設定します。
507                        // dbXMLResourceInsert の後に登録する必要があります。
508                        dbResourceUpdate( rscConn,sysParam );                   // 5.6.7.0 (2013/07/27) DBID=RESOURCE のコネクション
509                        rscConn.commit();
510        //              Closer.commit( rscConn );
511
512                        final Map<String,String> userMap = new HashMap<>(100);
513                        // 6.4.2.1 (2016/02/05) try-with-resources æ–‡
514                        try( PreparedStatement pstmt = rscConn.prepareStatement( QUERY ) ) {
515                                pstmt.setFetchSize( DB_FETCH_SIZE );            // 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ
516                                pstmt.setString( 1,SYSTEM_ID );
517                                pstmt.setString( 2,HOST_URL );                          // 4.1.0.0 (2007/12/21)
518                                try( ResultSet resultSet = pstmt.executeQuery() ) {
519
520                                        while( resultSet.next() ) {
521                                                final String key = resultSet.getString(1);
522                                                final String val = resultSet.getString(2);
523                                                // 6.4.3.2 (2016/02/19) null値の登録はやめます。
524                                                userMap.put( key,val == null ? "" : val );              // 6.4.3.2 (2016/02/19)
525                                        }
526                                }
527                        }
528
529                        // DBを検索して、ユーザー設定リソース情報を取得します。
530                        System.out.println( "    Load DB Resource [" + userMap.size() + "] finished." );
531                        // リソースをマージします。
532                        sysParam.putAll( userMap );
533                        errFlag = false;        // エラーでない
534                }
535                catch( final SQLException ex ) {
536                        Closer.rollback( defConn );                     // 5.6.7.0 (2013/07/27) DBID=DEFAULT のコネクション
537                        Closer.rollback( rscConn );                     // 5.6.7.0 (2013/07/27) DBID=RESOURCE のコネクション
538                        LogWriter.log( ex );
539                        final String errMsg = ex.getMessage() + ":" + ex.getSQLState() ;
540                        ERR_MSG_LIST.add( errMsg );
541                }
542                catch( final UnsupportedEncodingException ex ) {
543                        Closer.rollback( defConn );                     // 5.6.7.0 (2013/07/27) DBID=DEFAULT のコネクション
544                        Closer.rollback( rscConn );                     // 5.6.7.0 (2013/07/27) DBID=RESOURCE のコネクション
545                        LogWriter.log( ex );
546                        final String errMsg = "UTF-8 がサポートされていない Java VM は、正規VMではありません。"
547                                                        + ex.getMessage();
548                        ERR_MSG_LIST.add( errMsg );
549                }
550                catch( final RuntimeException ex ) {
551                        Closer.rollback( defConn );                     // 5.6.7.0 (2013/07/27) DBID=DEFAULT のコネクション
552                        Closer.rollback( rscConn );                     // 5.6.7.0 (2013/07/27) DBID=RESOURCE のコネクション
553                        // 5.7.2.0 (2014/01/10) RuntimeException は、catch しないようにします。
554                        // 6.4.7.1 (2016/06/17)
555                        final String errMsg = "システムパラメータの設定で、エラーが発生しました。"
556                                                        + ex.getMessage();
557                        ERR_MSG_LIST.add( errMsg );
558
559                        throw new HybsSystemException( ex );            // 6.4.3.2 (2016/02/19) 生のRuntimeExceptionをラップしてthrowする。
560                }
561                finally {
562                        if( errFlag ) {
563                                ConnectionFactory.remove( defConn, null );                              // 5.6.7.0 (2013/07/27) DBID=DEFAULT のコネクション
564                                ConnectionFactory.remove( rscConn, RESOURCE_DBID );             // 5.6.7.3 (2013/08/23) DBID=RESOURCE 漏れ
565                        }
566                        else {
567                                ConnectionFactory.close( defConn, null );                               // 5.6.7.0 (2013/07/27) DBID=DEFAULT のコネクション
568                                ConnectionFactory.close( rscConn, RESOURCE_DBID );              // 5.6.7.3 (2013/08/23) DBID=RESOURCE 漏れ
569                        }
570                }
571        }
572
573        /**
574         * エンジン内部定義の初期リソース情報をDB(GE12)に登録します。
575         *
576         * 初期リソース情報は、KBSAKU='0' で登録されている情報で、一旦すべて削除
577         * してから、全てのリソース情報を追加するという形をとります。
578         * ただし、属性情報(名称や概要など)を別途登録する場合は、全てを
579         * 削除せずに、UPDATE する方向で検討したいと思います。
580         * なお、この情報をDB登録する理由は、リソースの設定値を変えたい場合に、
581         * キーが判らない(JavaDOCからしか読み取れない)のでは不便な為に
582         * 用意しておくだけで、内部では SystemData オブジェクトとして定義
583         * されている値を使用するため、このデータベース値は、使用していません。
584         *
585         * ※ 6.9.7.0 (2018/05/14)
586         *    自身のサーバーで追記した情報以外を消すため、登録日付が古いデータは削除します。
587         *    現状は、1ヶ月にしています。
588         *
589         * @og.rev 6.9.7.0 (2018/05/14) DYSETの登録と、旧データ(1ヶ月前)の削除を行います。
590         * @og.rev 8.5.4.2 (2024/01/12) PMD 7.0.0 CloseResource 対応
591         *
592         * @param       conn    登録用コネクション(リソース用)
593         * @param       map             入力システムパラメータマップ
594         * @throws      SQLException    データベースアクセスエラー
595         */
596        private static void dbResourceUpdate( final Connection conn,final Map<String,String> map ) throws SQLException {
597
598                final String SYSTEM_ID = map.get( "SYSTEM_ID" );
599                final String HOST_URL  = map.get( "HOST_URL" );         // 4.1.0.0 (2007/12/21)
600
601                // 6.9.7.0 (2018/05/14) 現在時刻から、1ヶ月を引いた日付と比較して、削除データを決めます。
602                final Calendar now = Calendar.getInstance();
603                now.add( Calendar.MONTH , -1 );
604                final String OLD_DATE  = DateSet.getDate( now.getTimeInMillis() , DYSET_FORMAT );
605
606                // 既存の設定値を全件DELETEします。
607                int delCnt;
608                // 8.5.4.2 (2024/01/12) PMD 7.0.0 CloseResource 対応
609//              PreparedStatement pstmt = null;
610//              try {
611//                      pstmt = conn.prepareStatement( DEL_SYS );
612                try ( PreparedStatement pstmt = conn.prepareStatement( DEL_SYS ) ) {
613                        pstmt.setString( 1, SYSTEM_ID );
614                        pstmt.setString( 2, HOST_URL );                                         // 4.1.0.0 (2007/12/21)
615                        pstmt.setString( 3, OLD_DATE );                                         // 6.9.7.0 (2018/05/14) 古いデータを消します。
616                        delCnt = pstmt.executeUpdate();
617                }
618//              finally {
619//                      Closer.stmtClose( pstmt );
620//              }
621
622                // 新設定値を全件INSERTします。
623                final Set<String> keyset = map.keySet();
624//              final String[] keys = keyset.toArray( new String[keyset.size()] );
625                final String[] keys = keyset.toArray( new String[0] );  // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
626
627                final String DYSET = DateSet.getDate( DYSET_FORMAT );   // 6.9.7.0 (2018/05/14)
628                int insCnt = 0;
629                // 8.5.4.2 (2024/01/12) PMD 7.0.0 CloseResource 対応
630//              try {
631                try ( PreparedStatement pstmt = conn.prepareStatement( INS_SYS ) ) {
632//                      pstmt = conn.prepareStatement( INS_SYS );
633                        for( int i=0; i<keys.length; i++ ) {
634                                pstmt.setString( 1,SYSTEM_ID );                                 // SYSTEM_ID
635                                pstmt.setString( 2,HOST_URL);                                   // CONTXT_PATH
636                                pstmt.setString( 3,keys[i] );                                   // PARAM_ID
637                                pstmt.setInt(    4,( i + 1 ) * 10 );                    // SEQNO
638                                pstmt.setString( 5,map.get( keys[i] ) );                // PARAM
639                                pstmt.setString( 6,DYSET );                                             // DYSET 6.9.7.0 (2018/05/14)
640                                pstmt.setString( 7,keys[i] );                                   // PARAM_ID
641                                insCnt += pstmt.executeUpdate();
642                        }
643                }
644//              finally {
645//                      Closer.stmtClose( pstmt );
646//              }
647
648                System.out.print( "    DB Context Resource Reconfiguration " );
649                System.out.println( "DELETE=[" + delCnt + "],INSERT=[" + insCnt + "] finished." );
650        }
651
652        /**
653         * ServletContext の名称を取得します。
654         *
655         * コンテキストのアクセスされたパス( /training など )の名称を、
656         * 取得します。(アクセス先の仮想フォルダ名)
657         * 以前は、配備記述子(WEB-INF/web.xml)の display-name 要素を見て、
658         * 無ければ、実フォルダ名を返していました。
659         * ※ warファイルのバージョン管理(セッション管理)対応として、## 以下の文字列を削除します。
660         *    ## は、war化の際に、"%23%23" に変換されるため、それも取り除き処理の対象とします。
661         *
662         * @og.rev 6.6.0.0 (2016/12/01) コンテキストパスから、##バージョン番号を取り去った値を返すようにします。
663         *
664         * @param       context Servletコンテキスト
665         *
666         * @return      コンテキストのコンテキスト名
667         */
668        private static String getContextName( final ServletContext context ) {
669                String name = null;
670                try {
671                        final String path = context.getResource( "/" ).getFile();
672                        final int st = path.lastIndexOf( '/',path.length()-2 );         // 後ろから '/' を検索した位置(一番後ろは、'/' が付いているので注意)
673                        int ed = path.indexOf( "##",st+1 );                                                     // '/' 以降で、"##" を検索した位置
674                        if( ed < 0 ) {
675                                ed = path.indexOf( "%23%23",st+1 );                                             // '/' 以降で、"%23%23" を検索した位置
676                        }
677                        final int ed2 = ed > 0 ? ed : path.length()-1 ;                         // ## が無ければ、一番最後の文字を含まない、一つ前まで。あれば、そこまで
678                        name = path.substring( st+1,ed2 );
679                }
680                catch( final MalformedURLException ex ) {
681                        LogWriter.log( ex );
682                        final String errMsg = "このパス名は、正しいフォームではありません。 "
683                                                + ex.getMessage();
684                        ERR_MSG_LIST.add( errMsg );
685                }
686                return name ;
687        }
688
689        /**
690         * 指定のクラスの public static なフィールドキーと値のマップを作成します。
691         * 主に、エンジン関連のクラスにパラメータファイルをクラスとして定義し、
692         * エンジンとともに配布します。配布されたクラスを元に、パラメータを
693         * 読み取ります。
694         * この処理は リフレクションを使用してクラスの public static フィールドを
695         * 取得し、LinkedHashMap により、取得順をキープしたまま、Mapを返します。
696         *
697         * @og.rev 5.7.2.0 (2014/01/10) ERR_MSG_LIST は、一旦文字列に変換してから追加します。
698         * @og.rev 6.4.3.2 (2016/02/19) returnをやめて、引数のMapに直接値を設定します。
699         *
700         * @param       map     読み書きするMapオブジェクト
701         * @param       cls     クラスオブジェクト
702         */
703        private static void loadParameter( final Map<String,String> map , final Class<?> cls ) {
704
705                int cnt = 0;
706                try {
707                //      final Field[] field = cls.getFields(); の取得。public フィールドのみ
708                        for( final Field fld : cls.getFields() ) {
709                                if( Modifier.isStatic( fld.getModifiers() ) ) {
710                                        map.put( fld.getName() , (String)fld.get( null ) );
711                                        cnt++ ;
712                                }
713                        }
714                }
715                catch( final IllegalAccessException ex ) {
716                        LogWriter.log( ex );
717                        // 5.7.2.0 (2014/01/10) ERR_MSG_LIST は、一旦文字列に変換してから追加します。
718                        final String errMsg = "クラスから、パラメータを取得できませんでした。" + CR
719                                                                + "  クラス名=[" + cls.getName() + "]"                              + CR
720                                                                + ex.getMessage();
721                        ERR_MSG_LIST.add( errMsg );
722                }
723
724                System.out.println( "    ClassLoad " + cls.getName() + " Parameter [" + cnt + "] finished." );
725        }
726
727        /**
728         * 指定のキーワードのファイルをクラスパスより取得し、キーと値のマップを作成します。
729         * 主に、エンジン関連のクラスにパラメータファイルをPlugInクラスとして定義し、配布します。
730         * この処理の取得に、クラスパスの順序が関係します。最初に取得されたキーは、あとから
731         * 読み取られたクラスパスは、再セットしません。
732         *
733         * @og.rev 5.3.6.0 (2011/06/01) 並び順を、キーの名称順とする。
734         * @og.rev 5.7.2.0 (2014/01/10) ERR_MSG_LIST は、一旦文字列に変換してから追加します。
735         * @og.rev 5.7.2.0 (2014/01/10) RuntimeException は、catch しないようにします。
736         * @og.rev 6.4.3.2 (2016/02/19) returnをやめて、引数のMapに直接値を設定します。
737         * @og.rev 6.6.0.0 (2016/12/01) コンテキストパスから、##バージョン番号を取り去った値を返すようにします。
738         *
739         * @param       ioMap   読み書きするMapオブジェクト
740         * @param       keyword クラスオブジェクトを検索する元
741         */
742        private static void loadParameter( final Map<String,String> ioMap , final String keyword ) {
743                final Map<String,String> map = new TreeMap<>();         // 5.3.6.0 (2011/06/01) 並び順を、キーの名称順とする。
744                try {
745                        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
746                        final Enumeration<URL> enume = loader.getResources( keyword );          // 4.3.3.6 (2008/11/15) Generics警告対応
747                        while( enume != null && enume.hasMoreElements() ) {
748                                final URL url = enume.nextElement();            // 4.3.3.6 (2008/11/15) Generics警告対応
749                                // jar:file:/実ディレクトリ または、file:/実ディレクトリ
750                                final String dir = url.getFile().replaceAll( "%23%23","##" );   // 6.6.0.0 (2016/12/01)
751
752                                final FindClassFiles filenames = new FindClassFiles( dir,keyword );
753                                final String[] names = filenames.getFilenames();
754                                // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach
755//                              for( int i=0; i<names.length; i++ ) {
756//                                      final String val = names[i];
757                                for( final String val : names ) {
758                                        final String key = val.substring( val.lastIndexOf( '.' )+1 );
759                                        if( key.indexOf( '_' ) >= 0 && !map.containsKey( key ) && key.indexOf( '$' ) < 0 ) {
760                                                map.put( key , val );
761                                        }
762                                }
763                                System.out.println( "    FileCheck " + dir + " [" + names.length + "] find." );
764                        }
765                }
766                catch( final IOException ex ) {
767                        LogWriter.log( ex );
768                        // 5.7.2.0 (2014/01/10) ERR_MSG_LIST は、一旦文字列に変換してから追加します。
769                        final String errMsg = "キーワードから、パラメータを取得できませんでした。"       + CR
770                                                + "  キーワード名=[" + keyword + "]"                                          + CR
771                                                + ex.getMessage();
772                        ERR_MSG_LIST.add( errMsg );
773                }
774                // 5.7.2.0 (2014/01/10) RuntimeException は、catch しないようにします。
775                System.out.println( "    FileLoad " + keyword + " Parameter [" + map.size() + "] finished." );
776                ioMap.putAll( map );            // TreeMap で、キーの名称順に並んだMapを、LinkedHashMapに登録順に設定する。
777        }
778}