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