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.resource; 017 018import java.util.Map; 019import java.util.WeakHashMap; 020import java.util.Collections ; 021 022import org.opengion.hayabusa.common.HybsSystem; 023import org.opengion.fukurou.db.ApplicationInfo; 024import org.opengion.fukurou.db.DBUtil; 025import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 8.0.0.0 (2021/10/01) 026 027/** 028 * systemId に対応したカラムデータを作成するデータロードクラスです。 029 * 030 * カラムデータは、項目(CLM)に対して、各種カラム情報を持っています。 031 * エンジン内部で使用している DBColumn オブジェクトは、RENDERER や EDITOR など 032 * 実際にはオブジェクトで管理していますが、この ColumnData では、それらのキーとなる 033 * 文字列を持っています。実際に DBColumn オブジェクトの構築時に、各属性オブジェクトを 034 * 生成(または、キャッシュから取り出し)ます。 035 * 036 * カラムデータを作成する場合は、同一カラムで、作成区分(KBSAKU)違いの場合は、 037 * 最も大きな作成区分を持つコードを使用します。 038 * 作成区分(KBSAKU)='0' のデータは、マスタリソースとして、エンジンとともに 039 * 配布されるリソースになります。 040 * 041 * カラムデータには、3つのレベルのオブジェクト作成方法が適用されます。 042 * エンジン内部のカラムリソースファイル(org.opengion.hayabusa.common.data.ColumnResource)は、 043 * 初期作成されるカラムリソースです。エンジンの更新に対応して、このリソースも同時に 044 * 更新されます。このカラムは、最も優先順位の低いリソースで、同一キー情報で他の形式の 045 * カラムがあれば、そちらが使用されます。 046 * 047 * 読込フラグ(FGLOAD)='1'のカラムリソースは、すべて初期起動時に一括読み込みされます。 048 * 読込フラグが、'1' 以外のデータは、初期起動時には、メモリにキャッシュされず 049 * 実際に使用されるまで、オブジェクトが作成されません。 050 * これは、使用されるかどうか判らないカラムデータを、予め作成しないことで、メモリの 051 * 節約を図っています。 052 * 053 * SYSTEM_ID='**' は、共通リソースです。 054 * これは、システム間で共通に使用されるリソース情報を登録しておきます。 055 * 056 * @og.rev 4.0.0.0 (2004/12/31) 新規作成 057 * @og.group リソース管理 058 * 059 * @version 4.0 060 * @author Kazuhiko Hasegawa 061 * @since JDK5.0, 062 */ 063final class ColumnDataLoader { 064 // リソースの接続先を、取得します。 065 private final String DBID = HybsSystem.sys( "RESOURCE_DBID" ); 066 067// // DBリソースの初期一括読込のクエリー 068// // 7.3.1.3 (2021/03/09) 069// private static final String SEL_CLM = "select CLM,CLS_NAME,USE_LENGTH,VIEW_LENGTH" 070// + ",RENDERER,EDITOR,DBTYPE,DATA_DEFAULT,LABEL_CLM,CODE_CLM" 071// + ",CLM_PARAM,RENDERER_PARAM,EDITOR_PARAM,TYPE_PARAM,ROLES" 072// + ",'' AS FIELD_SIZE,FGLOAD,UNIQ,SYSTEM_ID,KBSAKU" ; 073 074 // 7.3.1.3 (2021/03/09) 075 // 7.4.5.0 (2021/08/31) Firebird 対応 076// private static final String QUERY = "select a.* from (" 077// + SEL_CLM + ",0 as SNO" 078// + " from GEA03 where SYSTEM_ID='**' and FGJ='1'" // エンジン共通 079// + " union all " 080// + SEL_CLM + ",1 as SNO" 081// + " from GEA03 where SYSTEM_ID=? and FGJ='1'" // RESOURCE_BASE_SYSTEM_ID 082// + " union all " 083// + SEL_CLM + ",2 as SNO" 084// + " from GEA03 where SYSTEM_ID=? and FGJ='1'" // 最上位ののSYSTEM_ID 085// + " ) a " // 8.0.0.0 (2021/08/31) 086// + " order by a.SNO,a.KBSAKU,a.CLM" ; 087 088 /** 8.0.0.0 (2021/10/01) RESOURCE_BASE_SYSTEM_ID は、SYSTEM_IDの配列で複数指定できる。 */ 089 private static final String QUERY = "select CLM,CLS_NAME,USE_LENGTH,VIEW_LENGTH" 090 + ",RENDERER,EDITOR,DBTYPE,DATA_DEFAULT,LABEL_CLM,CODE_CLM" 091 + ",CLM_PARAM,RENDERER_PARAM,EDITOR_PARAM,TYPE_PARAM,ROLES" 092 + ",'' AS FIELD_SIZE,FGLOAD,UNIQ,SYSTEM_ID,KBSAKU" 093 + " from GEA03 where SYSTEM_ID=? and FGJ='1'" // バインド変数 SYSTEM_ID=? 094 + " order by KBSAKU,CLM" ; 095 096// // DBリソースの個別読込時のクエリー 097 // 注意:CLMを unionする前に条件として入れたのでパラメータの順番が変わる。 098 // 7.3.1.3 (2021/03/09) 099 // 7.4.5.0 (2021/08/31) Firebird 対応 100// private static final String QUERY2 = "select a.* from (" 101// + SEL_CLM + ",0 as SNO" 102// + " from GEA03 where SYSTEM_ID='**' and CLM=? and FGJ='1'" // エンジン共通 103// + " union all " 104// + SEL_CLM + ",1 as SNO" 105// + " from GEA03 where SYSTEM_ID=? and CLM=? and FGJ='1'" // RESOURCE_BASE_SYSTEM_ID 106// + " union all " 107// + SEL_CLM + ",2 as SNO" 108// + " from GEA03 where SYSTEM_ID=? and CLM=? and FGJ='1'" // 最上位ののSYSTEM_ID 109// + " ) a " // 8.0.0.0 (2021/08/31) 110// + " order by a.SNO,a.KBSAKU,a.CLM" ; 111 112 /** 8.0.0.0 (2021/10/01) RESOURCE_BASE_SYSTEM_ID は、SYSTEM_IDの配列で複数指定できる。 */ 113 private static final String QUERY2 = "select CLM,CLS_NAME,USE_LENGTH,VIEW_LENGTH" 114 + ",RENDERER,EDITOR,DBTYPE,DATA_DEFAULT,LABEL_CLM,CODE_CLM" 115 + ",CLM_PARAM,RENDERER_PARAM,EDITOR_PARAM,TYPE_PARAM,ROLES" 116 + ",'' AS FIELD_SIZE,FGLOAD,UNIQ,SYSTEM_ID,KBSAKU" 117 + " from GEA03 where SYSTEM_ID=? and CLM=? and FGJ='1'" // バインド変数 SYSTEM_ID=? and CLM=? 118 + " order by KBSAKU DESC" ; // 逆順で検索し、先頭採用 119 120 /** 6.3.1.1 (2015/07/10) 読込フラグ(FGLOAD) のマーカー設定追加。 */ 121 private static final boolean IS_FGLOAD_AUTOSET = HybsSystem.sysBool( "USE_FGLOAD_AUTOSET" ); // 6.4.1.1 (2016/01/16) useFgloadAutoset → IS_FGLOAD_AUTOSET refactoring 122 123 /** 6.3.1.1 (2015/07/10) FGLOAD更新(UNIQ だけで指定可能だが、万一を想定して、SYSTEM_IDとCLMを条件に追記) */ 124 // 7.2.6.0 (2020/06/30) "**"以外にベースとなるSYSTEM_ID(RESOURCE_BASE_SYSTEM_ID)設定の対応したため、where条件から、SYSTEM_ID は削除します。 125 private static final String UPDATE2 = "update GEA03 set FGLOAD='2' where UNIQ=? and CLM=?"; 126 127 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。 */ 128 private final Map<String,ColumnData> columnMap = Collections.synchronizedMap( new WeakHashMap<>() ); // キャッシュ用プール 129 // 8.0.0.0 (2021/10/01) RESOURCE_BASE_SYSTEM_ID は、SYSTEM_IDの配列で複数指定できる。 130// private final String SYSTEM_ID ; // システムID 131// private final String BASE_SYS_ID ; // 7.2.9.2 (2020/10/30) ベースシステムID 132 private final String[] SYS_ARRAY; // 8.0.0.0 (2021/10/01) 133 134 /** コネクションにアプリケーション情報を追記するかどうか指定 */ 135 public static final boolean USE_DB_APPLICATION_INFO = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ; 136 137 /** 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定 */ 138 private final ApplicationInfo appInfo; 139 140 /** 141 * SystemId 毎に ファクトリオブジェクトを作成します。 142 * 143 * @og.rev 7.2.9.2 (2020/10/30) ベースとなるSYSTEM_ID(RESOURCE_BASE_SYSTEM_ID)の取得 144 * @og.rev 8.0.0.0 (2021/10/01) RESOURCE_BASE_SYSTEM_ID は、SYSTEM_IDの配列で複数指定できる。 145 * 146// * @param systemId システムID 147// * @param baseSys ベースとなるSYSTEM_ID 148 * @param sysAry 階層リソースの元となるSYSTEM_IDの配列(前方優先) 149 * @param initLoad リソースデータの先読み可否(true:先読みする) 150 */ 151// ColumnDataLoader( final String systemId,final String baseSys,final boolean initLoad ) { 152 /* default */ ColumnDataLoader( final String[] sysAry,final boolean initLoad ) { 153// SYSTEM_ID = systemId; 154// BASE_SYS_ID = baseSys ; // 7.2.9.2 (2020/10/30) 155 SYS_ARRAY = sysAry ; // 8.0.0.0 (2021/10/01) 156 157 // 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定 158 if( USE_DB_APPLICATION_INFO ) { 159 appInfo = new ApplicationInfo(); 160 // ユーザーID,IPアドレス,ホスト名 161// appInfo.setClientInfo( SYSTEM_ID,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME ); 162 appInfo.setClientInfo( SYS_ARRAY[0],HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME ); 163 // 画面ID,操作,プログラムID 164 appInfo.setModuleInfo( "ColumnDataLoader",null,null ); 165 } 166 else { 167 appInfo = null; 168 } 169 170 // ApplicationInfo の設定が終わってから実行します。 171 if( initLoad ) { loadDBResource(); } 172 } 173 174 /** 175 * DBリソースより カラムデータを取得、設定します。 176 * 同一キー(CLM)に対して、複数の作成区分(KBSAKU)を持つデータが 177 * 検索される場合は、作成区分(KBSAKU)の大きな値が使用されます。 178 * つまり、より、ローカライズなキーほど、作成区分(KBSAKU)に大きな値を 179 * 使用するようにします。 180 * 181 * ※ 以下のロジックは、後方優先であり、SYSTEM_IDの配列は前方優先なので逆順で回します。 182 * 183 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定 184 * @og.rev 4.3.5.7 (2009/03/22) FGLOADの影響でシステム個別リソースが読まれない問題対応 185 * @og.rev 7.0.7.0 (2019/12/13) 読み取り件数の評価を、破棄分も考慮する。 186 * @og.rev 7.2.6.0 (2020/06/30) "**"以外にベースとなるSYSTEM_ID(RESOURCE_BASE_SYSTEM_ID)設定の対応 187 * @og.rev 8.0.0.0 (2021/10/01) 階層リソースの元となるSYSTEM_IDの配列(前方優先)を使用する。 188 */ 189 private void loadDBResource() { 190 final int size = SYS_ARRAY.length; 191 192 final int[] cnt = new int[size]; // 各SYSTEM_ID の個数 193 int selCnt = 0; 194 for( int j=size-1; j>=0; j-- ) { // SYSTEM_IDの配列は、前方優先なので、逆順で回す必要がある。 195 final String sysId = SYS_ARRAY[j]; 196// final String[] args = new String[] { BASE_SYS_ID,SYSTEM_ID }; // 7.2.6.1 (2020/07/17) 197 // 8.5.4.2 (2024/01/12) PMD 7.0.0 UseShortArrayInitializer 198// final String[] args = new String[] { sysId } ; // 8.0.0.0 (2021/10/01) 199 final String[] args = { sysId } ; // 8.0.0.0 (2021/10/01) 200 201 final String[][] vals = DBUtil.dbExecute( QUERY,args,appInfo,DBID ); 202// final int[] cnt = new int[3]; // **,BASE_SYS_ID,SYSTEM_ID の個数 203 204 final int len = vals.length; 205 selCnt += len; 206 for( int i=0; i<len; i++ ) { 207 final String clm = vals[i][0]; 208// final int idx = Integer.parseInt( vals[i][ColumnData.SNO] ); 209 210 if( "1".equals( vals[i][ColumnData.FG_LOAD] ) ) { // 4.3.5.7 (2009/03/22) 1:一括読込 211 columnMap.put( clm,new ColumnData( vals[i] ) ); 212// cnt[idx]++ ; 213 cnt[j]++ ; 214 } 215 // より上の作成区分で、FGLOAD='1'(一括読込)以外の場合は、破棄する。 216 // order by SYSTEM_ID,CLM,KBSAKU 217 else if( columnMap.get( clm ) != null ){ 218 columnMap.remove( clm ); 219 } 220 } 221 } 222 223 // 7.0.7.0 (2019/12/13) 読み取り件数の評価を、破棄分も考慮する。 224// System.out.println( " ColumnDataLoader [" + len + "] select [" + columnMap.size() + "] " 225// + " ** [" + cnt[0] + "] " + BASE_SYS_ID + " [" + cnt[1] + "] " + SYSTEM_ID + " [" + cnt[2] + "] loaded" ); 226 227 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 228 buf.append( " " ).append( SYS_ARRAY[0] ).append( " ColumnDataLoader [" ).append( selCnt ) 229 .append( "] Map=[" ).append( columnMap.size() ).append( "] " ); 230 for( int j=0; j<size; j++ ) { 231 buf.append( SYS_ARRAY[j] ).append( "=[" ).append( cnt[j] ).append( "] " ); 232 } 233 buf.append( "loaded." ); 234 System.out.println( buf ); 235 } 236 237 /** 238 * ColumnDataオブジェクトを取得します。 239 * 作成したColumnDataオブジェクトは、内部にプールしておき、同じリソース要求が 240 * あったときは、プールの ColumnDataを返します。 241 * 読込フラグ(FGLOAD)が '1' のデータは、起動時に先読みします。 242 * それ以外のデータは、ここでキー要求が発生した時点で読み込みます。 243 * 読込フラグ(FGLOAD) のマーカー設定モード(USE_FGLOAD_AUTOSET)を使用する(true)場合は、 244 * 追加読み込み(先読みされていないカラム)に対して、読込フラグ(FGLOAD)を 2:使用実績 に 245 * 設定します。(次回起動時の、初期読み込みは行いません。) 246 * 247 * ※ 以下のロジックは、先に見つかった値を返すので、前方優先で検索します。 248 * 249 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為、ApplicationInfoオブジェクトを設定 250 * @og.rev 6.3.1.1 (2015/07/10) 読込フラグ(FGLOAD) のマーカー設定追加。 251// * @og.rev 7.0.7.0 (2019/12/13) FG_LOADが、3:使用確認 , 8:未使用 の場合に使用されると、2:使用実績 をセットする。 7.0.7.2 元に戻す 252 * @og.rev 7.0.7.0 (2019/12/13) キーだけからリソース無しのColumnDataを作成します。 253 * @og.rev 7.0.7.2 (2019/12/28) リソース無しのキャッシュは行わない。(DBからSELECTした際、スキーマから自動で文字か数字を判定しているから) 254 * @og.rev 7.2.6.0 (2020/06/30) "**"以外にベースとなるSYSTEM_ID(RESOURCE_BASE_SYSTEM_ID)設定の対応 255 * @og.rev 7.3.1.3 (2021/03/09) QUERY文字列を変更。それに伴って、引数の並び順を変更。 256 * @og.rev 8.0.0.0 (2021/10/01) 階層リソースの元となるSYSTEM_IDの配列(前方優先)を使用する。 257 * 258 * @param key カラムのキー 259 * 260 * @return ColumnDataオブジェクト 261 */ 262 public ColumnData getColumnData( final String key ) { 263 ColumnData column = columnMap.get( key ) ; 264 if( column == null ) { 265 final int size = SYS_ARRAY.length; 266 for( int j=0; j<size; j++ ) { // SYSTEM_IDの配列(前方優先)で、最初に見つかったキーを採用する。 267 final String sysId = SYS_ARRAY[j]; 268// final String[] args = new String[] { key,BASE_SYS_ID,key,SYSTEM_ID,key }; // 7.3.1.3 (2021/03/09) 269 // 8.5.4.2 (2024/01/12) PMD 7.0.0 UseShortArrayInitializer 270// final String[] args = new String[] { sysId,key }; // 8.0.0.0 (2021/10/01) 271 final String[] args = { sysId,key }; // 8.0.0.0 (2021/10/01) 272 final String[][] vals = DBUtil.dbExecute( QUERY2,args,appInfo,DBID ); // SYSTEM_ID='**' も含む 273 if( vals.length > 0 ) { 274// final int row=vals.length-1; // 最後の検索結果 275 final int row=0 ; // 最初の検索結果が有効 276 column = new ColumnData( vals[row] ); // 最初のデータ 277 columnMap.put( key,column ); 278 279 // 6.3.1.1 (2015/07/10) 読込フラグ(FGLOAD) のマーカー設定追加。 280 if( IS_FGLOAD_AUTOSET ) { 281 // 1:一括読込 と、2:使用実績 以外のリソースは、2:使用実績 をセットする。(SYSTEM_ID='**'は含まない) 282 final String fgld = vals[row][ColumnData.FG_LOAD]; 283 final String sysld = vals[row][ColumnData.SYSTEM_ID]; 284 if( !"1".equals( fgld ) && !"2".equals( fgld ) && !"**".equals( sysld ) ) { 285 // 7.2.6.0 (2020/06/30) RESOURCE_BASE_SYSTEM_ID 追加したため、where条件から、SYSTEM_ID は削除します。 286 // 8.5.4.2 (2024/01/12) PMD 7.0.0 UseShortArrayInitializer 287// final String[] args2 = new String[] { vals[row][ColumnData.UNIQ],key }; 288 final String[] args2 = { vals[row][ColumnData.UNIQ],key }; 289 DBUtil.dbExecute( UPDATE2,args2,appInfo,DBID ); // FGLOAD を、2:使用実績 にセット 290 } 291 } 292 break; // 8.0.0.0 (2021/10/01) 逆順検索しているので、最初の検索結果が有効 293 } 294 } 295 } 296 return column ; 297 } 298 299 /** 300 * ColumnData オブジェクトのキャッシュを個別にクリアします。 301 * リソースデータの更新など、一部分の更新時に、すべてのキャッシュを 302 * 破棄するのではなく、指定の分のみ破棄できる機能です。 303 * 304 * @og.rev 6.9.0.1 (2018/02/05) どのシステムIDのリソースがクリアされたかを表示します。 305 * 306 * @param key カラムのキー 307 */ 308 public void clear( final String key ) { 309// System.out.println( "SYSTEM_ID=[" + SYSTEM_ID + "] , Key=[" + key + "] の部分リソースクリアを実施しました。" ); 310 System.out.println( "SYSTEM_ID=[" + SYS_ARRAY[0] + "] , Key=[" + key + "] の部分リソースクリアを実施しました。" ); 311 columnMap.remove( key ); 312 } 313 314 /** 315 * ColumnData オブジェクトのキャッシュをクリアします。 316 * 317 * @og.rev 6.9.0.1 (2018/02/05) どのシステムIDのリソースがクリアされたかを表示します。 318 * 319 */ 320 public void clear() { 321// System.out.println( "SYSTEM_ID=[" + SYSTEM_ID + "] の全リソースをクリアしました。" ); 322 System.out.println( "SYSTEM_ID=[" + SYS_ARRAY[0] + "] の全リソースをクリアしました。" ); 323 columnMap.clear(); 324 } 325}