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.util.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 public static final String QUERY = "select CLM,CODE,'','',CODELVL,CODEGRP,CODE_PARAM,ROLES,SYSTEM_ID,KBSAKU,'',''" // 5.6.8.2 (2013/09/20) 066 + " from GEA04 where SYSTEM_ID in ( ?,'**') and FGJ='1'" 067 + " order by SYSTEM_ID,KBSAKU,CLM,SEQNO,CODELVL,CODE" ; 068 069 /** DBリソースの個別読み込み時のクエリー */ 070 // 5.1.9.0 (2010/08/01) order by 変更 071 public static final String QUERY2 = "select CLM,CODE,'','',CODELVL,CODEGRP,CODE_PARAM,ROLES,SYSTEM_ID,KBSAKU,'',''" // 5.6.8.2 (2013/09/20) 072 + " from GEA04 where SYSTEM_ID in ( ?,'**') and FGJ='1' and CLM=?" 073 + " order by SYSTEM_ID,KBSAKU,CLM,SEQNO,CODELVL,CODE" ; 074 075 private final Map<String,CodeData> pool = Collections.synchronizedMap( new WeakHashMap<String,CodeData>() ); // キャッシュ用プール 076 private final String SYSTEM_ID ; // システムID 077 078 /** コネクションにアプリケーション情報を追記するかどうか指定 */ 079 public static final boolean USE_DB_APPLICATION_INFO = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ; 080 081 // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 082 private final ApplicationInfo appInfo; 083 084 private final LabelDataLoader LABEL_LOADER; // 見直し要!!! 085 086 /** 087 * lang 毎に ファクトリオブジェクトを作成します。 088 * 089 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 090 * 091 * @param systemId システムID 092 * @param initLoad リソースデータの先読み可否(true:先読みする) 093 * @param lLoader ラベルデータローダー 094 */ 095 CodeDataLoader( final String systemId,final boolean initLoad,final LabelDataLoader lLoader) { 096 SYSTEM_ID = systemId; 097 LABEL_LOADER = lLoader; 098 099 // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 100 if( USE_DB_APPLICATION_INFO ) { 101 appInfo = new ApplicationInfo(); 102 // ユーザーID,IPアドレス,ホスト名 103 appInfo.setClientInfo( SYSTEM_ID,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME ); 104 // 画面ID,操作,プログラムID 105 appInfo.setModuleInfo( "CodeDataLoader",null,null ); 106 } 107 else { 108 appInfo = null; 109 } 110 111 // ApplicationInfo の設定が終わってから実行します。 112 if( initLoad ) { loadDBResource(); } 113 } 114 115 /** 116 * DBリソースより コードデータを取得、設定します。 117 * 118 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定 119 * @og.rev 4.3.8.0 (2009/08/01) rawShortLabel追加 120 * @og.rev 5.6.8.2 (2013/09/20) rawLongLabel対応 121 */ 122 private void loadDBResource() { 123 String[] args = new String[] { SYSTEM_ID }; 124 125 String[][] vals = DBUtil.dbExecute( QUERY,args,appInfo,DBID ); 126 127 Map<String,Map<String,String[]>> clmMap = new HashMap<String,Map<String,String[]>>(); 128 int len = vals.length; 129 String bkClm = null; // キーブレイク 130 String bkSystem = null; 131 String bkKbsaku = null; 132 // 以下の処理は、SYSTEM_ID違いを塊で処理します。(混在させません。) 133 Map<String,String[]> codeMap = null; 134 for( int i=0; i<len; i++ ) { 135 String clm = vals[i][CodeData.CLM]; 136 String code = vals[i][CodeData.CODE]; 137 String systemId = vals[i][CodeData.SYSTEM_ID]; 138 String kbsaku = vals[i][CodeData.KBSAKU]; 139 if( bkClm == null || !bkClm.equals( clm ) || !bkSystem.equals(systemId) || !bkKbsaku.equals(kbsaku) ) { 140 codeMap = new LinkedHashMap<String,String[]>(); 141 clmMap.put( clm,codeMap ); 142 bkClm = clm; 143 bkSystem = systemId; 144 bkKbsaku = kbsaku; 145 } 146 147 String lkey = clm+"."+code; // やっつけ~ 148 vals[i][CodeData.LNAME] = LABEL_LOADER.getLabelData(lkey).getLongLabel(); 149 vals[i][CodeData.SNAME] = LABEL_LOADER.getLabelData(lkey).getShortLabel(); 150 vals[i][CodeData.RSNAME] = LABEL_LOADER.getLabelData(lkey).getRawShortLabel(); // 4.3.8.0 (2009/08/01) spanが付かない名前短 151 vals[i][CodeData.RLNAME] = LABEL_LOADER.getLabelData(lkey).getRawLongLabel(); // 5.6.8.2 (2013/09/01) 加工していない名前長 152 153 codeMap.put( code,vals[i] ); 154 } 155 156 String[] clmKeys = clmMap.keySet().toArray( new String[clmMap.size()] ); 157 int size = clmKeys.length; 158 for( int i=0; i<size; i++ ) { 159 String clm = clmKeys[i]; 160 codeMap = clmMap.get( clm ); 161 162 pool.put( clm,new CodeData( clm,codeMap ) ); 163 } 164 165 System.out.println( " CodeDataLoader [" + size + "] loaded" ); 166 } 167 168 /** 169 * CodeData オブジェクトを取得します。 170 * 作成したCodeDataオブジェクトは,内部にプールしておき,同じリソース要求が 171 * あったときは,プールの CodeDataを返します。 172 * 173 * @og.rev 4.3.8.0 (2009/08/01) rawShortLabel追加 174 * @og.rev 5.6.8.2 (2013/09/20) rawLongLabel追加 175 * 176 * @param key コードのキー 177 * 178 * @return CodeData オブジェクト 179 */ 180 public CodeData getCodeData( final String key ) { 181 CodeData codeData = pool.get( key ) ; 182 183 if( codeData == null ) { 184 String[] args = new String[] { SYSTEM_ID,key }; 185 String[][] vals = DBUtil.dbExecute( QUERY2,args,appInfo,DBID ); 186 187 int len = vals.length; 188 String bkSystem = null; // キーブレイク 189 String bkKbsaku = null; 190 // 以下の処理は、SYSTEM_ID違いを塊で処理します。(混在させません。) 191 Map<String,String[]> codeMap = null; 192 for( int i=0; i<len; i++ ) { 193 String systemId = vals[i][CodeData.SYSTEM_ID]; 194 String code = vals[i][CodeData.CODE]; 195 String kbsaku = vals[i][CodeData.KBSAKU]; 196 if( bkSystem == null || !bkSystem.equals( systemId ) || !bkKbsaku.equals(kbsaku) ) { 197 codeMap = new LinkedHashMap<String,String[]>(); 198 bkSystem = systemId; 199 bkKbsaku = kbsaku; 200 } 201 202 String lkey = key+"."+code; // やっつけ~ 203 vals[i][CodeData.LNAME] = LABEL_LOADER.getLabelData(lkey).getLongLabel(); 204 vals[i][CodeData.SNAME] = LABEL_LOADER.getLabelData(lkey).getShortLabel(); 205 vals[i][CodeData.RSNAME] = LABEL_LOADER.getLabelData(lkey).getRawShortLabel(); // 4.3.8.0 (2009/08/01) spanが付かない名前短 206 vals[i][CodeData.RLNAME] = LABEL_LOADER.getLabelData(lkey).getRawLongLabel(); // 5.6.8.2 (2013/09/20) 加工していない名前長 207 208 codeMap.put( code,vals[i] ); 209 } 210 211 if( codeMap != null ) { 212 codeData = new CodeData( key,codeMap ); 213 pool.put( key,codeData ); 214 } 215 } 216 return codeData ; 217 } 218 219 /** 220 * CodeData オブジェクトを取得します。 221 * 作成したCodeDataオブジェクトは,内部にプールしておき,同じリソース要求が 222 * あったときは,プールの CodeDataを返します。 223 * 224 * 引数にQUERYを渡すことで、DBから、動的にコードリソースを作成できます。 225 * 引数の順番は、CodeData で定義している CLM,CODE,LNAME,SNAME の順番のままです。 226 * QUERY には、key を引数にとる必要があります。つまり、WHERE CLM = ? の様な記述が必要です。 227 * 228 * @og.rev 5.4.2.2 (2011/12/14) 新規追加。 229 * 230 * @param key コードのキー 231 * @param query 検索SQL(引数に、? を一つ持つ) 232 * 233 * @return CodeData オブジェクト 234 */ 235 public CodeData getCodeData( final String key,final String query ) { 236 CodeData codeData = pool.get( key ) ; 237 238 if( codeData == null ) { 239 String[] args = new String[] { key }; 240 String[][] vals = DBUtil.dbExecute( query,args,appInfo,DBID ); 241 242 int len = vals.length; 243 Map<String,String[]> codeMap = new LinkedHashMap<String,String[]>(); 244 for( int i=0; i<len; i++ ) { 245 String[] cdVals = new String[CodeData.MAX_LENGTH]; // 空の配列を毎回作成 246 247 String code = vals[i][CodeData.CODE]; 248 249 cdVals[CodeData.CLM] = key ; 250 cdVals[CodeData.CODE] = code; 251 cdVals[CodeData.LNAME] = vals[i][CodeData.LNAME]; 252 cdVals[CodeData.SNAME] = vals[i][CodeData.SNAME]; 253 254 codeMap.put( code,cdVals ); 255 } 256 257 if( ! codeMap.isEmpty() ) { 258 codeData = new CodeData( key,codeMap ); 259 pool.put( key,codeData ); 260 } 261 } 262 return codeData ; 263 } 264 265 /** 266 * CodeData オブジェクトのキャッシュを個別にクリアします。 267 * リソースデータの更新など、一部分の更新時に、すべてのキャッシュを 268 * 破棄するのではなく、指定の分のみ破棄できる機能です。 269 * 270 * @og.rev 4.0.2.0 (2007/12/25) コードリソースクリア時に対応するラベルリソースもクリアする。 271 * 272 * @param key コードのキー 273 */ 274 public void clear( final String key ) { 275 276 // 4.0.2.0 (2007/12/25) 277 CodeData cdata = pool.remove( key ); 278 if( cdata != null ) { 279 String clm = cdata.getColumn(); 280 for( int i=0; i<cdata.getSize(); i++ ) { 281 LABEL_LOADER.clear( clm + '.' + cdata.getCodeKey( i ) ); 282 } 283 } 284 } 285 286 /** 287 * CodeData オブジェクトのキャッシュをクリアして、再作成します。 288 * 289 */ 290 public void clear() { 291 pool.clear(); 292 } 293}