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 org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.fukurou.db.ApplicationInfo; 020import org.opengion.fukurou.db.DBUtil; 021 022import java.util.Map; 023import java.util.HashMap; 024import java.util.LinkedHashMap ; 025import java.util.WeakHashMap ; 026import java.util.Collections ; 027 028/** 029 * コードオブジェクトを作成するデータロードクラスです。 030 * systemId と lang に対応したコードオブジェクトを作成します。 031 * 032 * コードオブジェクトは、項目(CLM)に対して、複数のコード(CODE)を持っています。 033 * この複数のコードを表示順に持つことで、プルダウンメニュー等の表示順を指定します。 034 * 035 * コードオブジェクトを作成する場合は、同一項目・コードで、作成区分(KBSAKU)違いの場合は、 036 * 最も大きな作成区分を持つコードを使用します。 037 * 作成区分(KBSAKU)は、他のリソースと異なり、同一項目・コード単位に設定すべきです。 038 * これは、通常は項目単位に作成区分を持つべきところを、コード単位でしか 039 * 持てないデータベースの設計になっている為です。アプリケーション側で設定条件を 040 * きちんと管理すれば、作成区分を使用できますが、一般にはお奨めできません。 041 * 作成区分(KBSAKU)='0' のデータは、マスタリソースとして、エンジンとともに 042 * 配布されるリソースになります。 043 * 044 * 読み込みフラグ(FGLOAD)は、使用しません。 045 * コードリソースに関しては、システム起動時に、すべてのコードリソースをエンジン内部 046 * に取り込みます。ただし、リソースのキャッシュに、WeakHashMap クラスを使用しているため、 047 * メモリオーバー時には、クリアされるため、単独での読み取りも行います。 048 * SYSTEM_ID='**' は、共通リソースです。 049 * これは、システム間で共通に使用されるリソース情報を登録しておきます。 050 * 051 * @og.rev 4.0.0.0 (2004/12/31) 新規作成 052 * @og.group リソース管理 053 * 054 * @version 4.0 055 * @author Kazuhiko Hasegawa 056 * @since JDK5.0, 057 */ 058final class CodeDataLoader { 059 // リソースの接続先を、取得します。 060 private final String DBID = HybsSystem.sys( "RESOURCE_DBID" ); 061 062 /** DBリソースの初期一括読み込みのクエリー */ 063 // キーブレイクで、SYSTEM_ID 違いは、まとめて処理する為、最初に ORDER BY しておく必要があります。 064 // 5.1.9.0 (2010/08/01) order by 変更 065 // 6.2.0.0 (2015/02/27) Description 追加に伴うQUERY桁数変更 066 public static final String QUERY = "select CLM,CODE,'','',CODELVL,CODEGRP,CODE_PARAM,ROLES,SYSTEM_ID,KBSAKU,'','',''" // 6.2.0.0 (2015/02/27) 067 + " from GEA04 where SYSTEM_ID in ( ?,'**') and FGJ='1'" 068 + " order by SYSTEM_ID,KBSAKU,CLM,SEQNO,CODELVL,CODE" ; 069 070 /** DBリソースの個別読み込み時のクエリー */ 071 // 5.1.9.0 (2010/08/01) order by 変更 072 // 6.2.0.0 (2015/02/27) Description 追加に伴うQUERY桁数変更 073 public static final String QUERY2 = "select CLM,CODE,'','',CODELVL,CODEGRP,CODE_PARAM,ROLES,SYSTEM_ID,KBSAKU,'','',''" // 6.2.0.0 (2015/02/27) 074 + " from GEA04 where SYSTEM_ID in ( ?,'**') and FGJ='1' and CLM=?" 075 + " order by SYSTEM_ID,KBSAKU,CLM,SEQNO,CODELVL,CODE" ; 076 077 /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。 */ 078 private final Map<String,CodeData> codeDtMap = Collections.synchronizedMap( new WeakHashMap<>() ); // キャッシュ用プール 079 private final String SYSTEM_ID ; // システムID 080 081 /** コネクションにアプリケーション情報を追記するかどうか指定 */ 082 public static final boolean USE_DB_APPLICATION_INFO = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ; 083 084 // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 085 private final ApplicationInfo appInfo; 086 087 private final LabelDataLoader LABEL_LOADER; // 見直し要!!! 088 089 /** 090 * lang 毎に ファクトリオブジェクトを作成します。 091 * 092 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 093 * 094 * @param systemId システムID 095 * @param initLoad リソースデータの先読み可否(true:先読みする) 096 * @param lLoader ラベルデータローダー 097 */ 098 CodeDataLoader( final String systemId,final boolean initLoad,final LabelDataLoader lLoader) { 099 SYSTEM_ID = systemId; 100 LABEL_LOADER = lLoader; 101 102 // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 103 if( USE_DB_APPLICATION_INFO ) { 104 appInfo = new ApplicationInfo(); 105 // ユーザーID,IPアドレス,ホスト名 106 appInfo.setClientInfo( SYSTEM_ID,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME ); 107 // 画面ID,操作,プログラムID 108 appInfo.setModuleInfo( "CodeDataLoader",null,null ); 109 } 110 else { 111 appInfo = null; 112 } 113 114 // ApplicationInfo の設定が終わってから実行します。 115 if( initLoad ) { loadDBResource(); } 116 } 117 118 /** 119 * DBリソースより コードデータを取得、設定します。 120 * 121 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 122 * @og.rev 4.3.8.0 (2009/08/01) rawShortLabel追加 123 * @og.rev 5.6.8.2 (2013/09/20) rawLongLabel対応 124 * @og.rev 6.2.0.0 (2015/02/27) description 概要説明 追加 125 */ 126 private void loadDBResource() { 127 final String[] args = new String[] { SYSTEM_ID }; 128 129 String[][] vals = DBUtil.dbExecute( QUERY,args,appInfo,DBID ); 130 131 final Map<String,Map<String,String[]>> clmMap = new HashMap<>(); 132 final int len = vals.length; 133 String bkClm = null; // キーブレイク 134 String bkSystem = null; 135 String bkKbsaku = null; 136 // 以下の処理は、SYSTEM_ID違いを塊で処理します。(混在させません。) 137 Map<String,String[]> codeMap = null; 138 for( int i=0; i<len; i++ ) { 139 final String clm = vals[i][CodeData.CLM]; 140 final String code = vals[i][CodeData.CODE]; 141 final String systemId = vals[i][CodeData.SYSTEM_ID]; 142 final String kbsaku = vals[i][CodeData.KBSAKU]; 143 if( bkClm == null || !bkClm.equals( clm ) || !bkSystem.equals( systemId ) || !bkKbsaku.equals( kbsaku ) ) { 144 codeMap = new LinkedHashMap<>(); 145 clmMap.put( clm,codeMap ); 146 bkClm = clm; 147 bkSystem = systemId; 148 bkKbsaku = kbsaku; 149 } 150 151 final String lkey = clm+"."+code; // やっつけ~ 152 // 6.2.0.0 (2015/02/27) 変数使用 153 final LabelData lblData = LABEL_LOADER.getLabelData(lkey); 154 vals[i][CodeData.LNAME] = lblData.getLongLabel(); 155 vals[i][CodeData.SNAME] = lblData.getShortLabel(); 156 vals[i][CodeData.RSNAME] = lblData.getRawShortLabel(); // 4.3.8.0 (2009/08/01) spanが付かない名前短 157 vals[i][CodeData.RLNAME] = lblData.getRawLongLabel(); // 5.6.8.2 (2013/09/01) 加工していない名前長 158 vals[i][CodeData.DESCRIPT] = lblData.getDescription(); // 6.2.0.0 (2015/02/27) 概要説明 159 160 codeMap.put( code,vals[i] ); 161 } 162 163 final String[] clmKeys = clmMap.keySet().toArray( new String[clmMap.size()] ); 164 final int size = clmKeys.length; 165 for( int i=0; i<size; i++ ) { 166 final String clm = clmKeys[i]; 167 codeMap = clmMap.get( clm ); 168 169 codeDtMap.put( clm,new CodeData( clm,codeMap ) ); 170 } 171 172 System.out.println( " CodeDataLoader [" + size + "] loaded" ); 173 } 174 175 /** 176 * CodeData オブジェクトを取得します。 177 * 作成したCodeDataオブジェクトは,内部にプールしておき,同じリソース要求が 178 * あったときは,プールの CodeDataを返します。 179 * 180 * @og.rev 4.3.8.0 (2009/08/01) rawShortLabel追加 181 * @og.rev 5.6.8.2 (2013/09/20) rawLongLabel追加 182 * @og.rev 6.2.0.0 (2015/02/27) description 概要説明 追加 183 * 184 * @param key コードのキー 185 * 186 * @return CodeDataオブジェクト 187 */ 188 public CodeData getCodeData( final String key ) { 189 CodeData codeData = codeDtMap.get( key ) ; 190 191 if( codeData == null ) { 192 final String[] args = new String[] { SYSTEM_ID,key }; 193 String[][] vals = DBUtil.dbExecute( QUERY2,args,appInfo,DBID ); 194 195 final int len = vals.length; 196 String bkSystem = null; // キーブレイク 197 String bkKbsaku = null; 198 // 以下の処理は、SYSTEM_ID違いを塊で処理します。(混在させません。) 199 Map<String,String[]> codeMap = null; 200 for( int i=0; i<len; i++ ) { 201 final String systemId = vals[i][CodeData.SYSTEM_ID]; 202 final String code = vals[i][CodeData.CODE]; 203 final String kbsaku = vals[i][CodeData.KBSAKU]; 204 if( bkSystem == null || !bkSystem.equals( systemId ) || !bkKbsaku.equals( kbsaku ) ) { 205 codeMap = new LinkedHashMap<>(); 206 bkSystem = systemId; 207 bkKbsaku = kbsaku; 208 } 209 210 final String lkey = key+"."+code; // やっつけ~ 211 // 6.2.0.0 (2015/02/27) 変数使用 212 final LabelData lblData = LABEL_LOADER.getLabelData(lkey); 213 vals[i][CodeData.LNAME] = lblData.getLongLabel(); 214 vals[i][CodeData.SNAME] = lblData.getShortLabel(); 215 vals[i][CodeData.RSNAME] = lblData.getRawShortLabel(); // 4.3.8.0 (2009/08/01) spanが付かない名前短 216 vals[i][CodeData.RLNAME] = lblData.getRawLongLabel(); // 5.6.8.2 (2013/09/01) 加工していない名前長 217 vals[i][CodeData.DESCRIPT] = lblData.getDescription(); // 6.2.0.0 (2015/02/27) 概要説明 218 219 codeMap.put( code,vals[i] ); 220 } 221 222 if( codeMap != null ) { 223 codeData = new CodeData( key,codeMap ); 224 codeDtMap.put( key,codeData ); 225 } 226 } 227 return codeData ; 228 } 229 230 /** 231 * CodeData オブジェクトを取得します。 232 * 作成したCodeDataオブジェクトは,内部にプールしておき,同じリソース要求が 233 * あったときは,プールの CodeDataを返します。 234 * 235 * 引数にQUERYを渡すことで、DBから、動的にコードリソースを作成できます。 236 * 引数の順番は、CodeData で定義している CLM,CODE,LNAME,SNAME の順番のままです。 237 * QUERY には、key を引数にとる必要があります。つまり、WHERE CLM = ? の様な記述が必要です。 238 * 239 * @og.rev 5.4.2.2 (2011/12/14) 新規追加。 240 * 241 * @param key コードのキー 242 * @param query 検索SQL(引数に、? を一つ持つ) 243 * 244 * @return CodeDataオブジェクト 245 */ 246 public CodeData getCodeData( final String key,final String query ) { 247 CodeData codeData = codeDtMap.get( key ) ; 248 249 if( codeData == null ) { 250 final String[] args = new String[] { key }; 251 final String[][] vals = DBUtil.dbExecute( query,args,appInfo,DBID ); 252 253 final int len = vals.length; 254 final Map<String,String[]> codeMap = new LinkedHashMap<>(); 255 for( int i=0; i<len; i++ ) { 256 String[] cdVals = new String[CodeData.MAX_LENGTH]; // 空の配列を毎回作成 257 258 final String code = vals[i][CodeData.CODE]; 259 260 cdVals[CodeData.CLM] = key ; 261 cdVals[CodeData.CODE] = code; 262 cdVals[CodeData.LNAME] = vals[i][CodeData.LNAME]; 263 cdVals[CodeData.SNAME] = vals[i][CodeData.SNAME]; 264 265 codeMap.put( code,cdVals ); 266 } 267 268 if( ! codeMap.isEmpty() ) { 269 codeData = new CodeData( key,codeMap ); 270 codeDtMap.put( key,codeData ); 271 } 272 } 273 return codeData ; 274 } 275 276 /** 277 * CodeData オブジェクトのキャッシュを個別にクリアします。 278 * リソースデータの更新など、一部分の更新時に、すべてのキャッシュを 279 * 破棄するのではなく、指定の分のみ破棄できる機能です。 280 * 281 * @og.rev 4.0.2.0 (2007/12/25) コードリソースクリア時に対応するラベルリソースもクリアする。 282 * 283 * @param key コードのキー 284 */ 285 public void clear( final String key ) { 286 287 // 4.0.2.0 (2007/12/25) 288 final CodeData cdata = codeDtMap.remove( key ); 289 if( cdata != null ) { 290 final String clm = cdata.getColumn(); 291 for( int i=0; i<cdata.getSize(); i++ ) { 292 LABEL_LOADER.clear( clm + '.' + cdata.getCodeKey( i ) ); 293 } 294 } 295 } 296 297 /** 298 * CodeData オブジェクトのキャッシュをクリアして、再作成します。 299 * 300 */ 301 public void clear() { 302 codeDtMap.clear(); 303 } 304}