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.Arrays; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.LinkedHashMap; 023import java.util.Map; 024import java.util.Set; 025 026import org.opengion.fukurou.util.ErrMsg; 027import org.opengion.fukurou.util.StringUtil; 028import org.opengion.hayabusa.common.HybsSystem; 029import org.opengion.hayabusa.db.DBColumn; 030import org.opengion.hayabusa.db.DBColumnConfig; 031 032/** 033 * java.util.ResourceBundle クラスを複数管理するリソースクラスです。 034 * 035 * ResourceManager は、 036 * LabelResource.properties ラベルリソース(テーブル定義やカラム名などの画面に表示するリソース) 037 * CodeResource.properties コードリソース(選択データなどプルダウンメニューで選択するリソース) 038 * MessageResource.properties メッセージリソース(エラーコードやメッセージなどを表示するリソース) 039 * 040 * の3つのプロパティーファイルを内部に持っており,それぞれのメソッドにより, 041 * リソースの返す値を決めています。 042 * 043 * ResourceManagerは,単独でも生成できますが,各ユーザー毎に作成するよりも 044 * ResourceFactory#newInstance( lang )メソッドより生成した方が,プーリングされるので 045 * 効率的です。 046 * 047 * リソース作成時に指定するロケールは,ISO 言語コード(ISO-639 で定義される 2 桁の小文字) 048 * <a href ="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt"> 049 * http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt</a>を使用して下さい。 050 * ただし,内部的に Locale を構築していますが,その正しさは,チェックされていませんので, 051 * 指定するロケールに応じた properties ファイルを用意しておいて下さい。 052 * 053 * 日本語の場合は, 言語コードは "jp" なので, 054 * LabelResource_jp.properties ラベルリソース(日本語) 055 * CodeResource_jp.properties コードリソース(日本語) 056 * MessageResource_jp.properties メッセージリソース(日本語) 057 * 058 * を用意して下さい。 059 * 060 * CodeResource については、リソースファイルから CodeSelectionオブジェクトを 061 * 作成して利用します。この、CodeSelectionオブジェクトの作成方法として、 062 * 3通り考えられます。 063 * 1つ目は、毎回 要求が発生する毎に CodeSelection を作成し、プールしていきます。こうすることで、 064 * 初めて使用されたときだけオブジェクト化されますので、メモリの節約が可能です。ただし、 065 * プールにヒットしなかった場合は、やはりリソースから検索しますので、元々ヒットしない 066 * キーに対しては、毎回リソースを検索するため、非効率です。 067 * 2つめは、元々ヒットしないキーに対して、NullCodeSelectionオブジェクトを登録しておくことで、 068 * プールにため込んで行くと言う方法です。この場合は、シングルトーンにしてメモリを節約しますが、 069 * それでもプール自体の容量は、確保しておく必要があります。 070 * 3つめは、この ResourceManager がインスタンス化されるときに、すべての CodeSelectionオブジェクトを 071 * あらかじめ プールしておく方法です。使わない CodeSelection もインスタンス化する変わりに、 072 * キャッシュにヒットしない場合は、即 CodeSelection が存在しないと判断できるため、 073 * もっともパフォーマンスが高くなります。 074 * 本 ResourceManager の実装は、3つめの、あらかじめ、すべてをキャッシュしておく方法を 075 * 採用しています。 076 * 077 * @og.group リソース管理 078 * 079 * @version 4.0 080 * @author Kazuhiko Hasegawa 081 * @since JDK5.0, 082 */ 083public final class ResourceManager { 084 private final ColumnDataLoader columnLoader ; 085 private final CodeDataLoader codeLoader; 086 private final LabelDataLoader labelLoader; 087 private final GUIDataLoader guiLoader; 088 089 private final Map<String,DBColumn> columnPool = Collections.synchronizedMap( new HashMap<String,DBColumn>( HybsSystem.BUFFER_LARGE ) ); 090 private final String lang ; 091 092 /** 093 * コンストラクター 094 * システムIDと言語コードを指定して,生成します。 095 * 096 * @param systemId システムID 097 * @param lg 言語コード 098 * @param initLoad リソースデータの先読み可否(true:先読みする) 099 */ 100 public ResourceManager( final String systemId,final String lg,final boolean initLoad ) { 101 this.lang = lg; 102 103 columnLoader = new ColumnDataLoader( systemId,initLoad ); 104 labelLoader = new LabelDataLoader( systemId,lang,initLoad ); 105 codeLoader = new CodeDataLoader( systemId,initLoad,labelLoader ); // 4.0.0.0(2007/10/17) 106 guiLoader = new GUIDataLoader( systemId ); 107 } 108 109 /** 110 * 設定されている言語を返します。 111 * 112 * @return 言語 113 */ 114 public String getLang() { 115 return lang; 116 } 117 118 /** 119 * DBColumn オブジェクトを取得します。 120 * 作成したDBColumnオブジェクトは,内部にプールしておき,同じオブジェクト要求が 121 * あったときは,プールのオブジェクトを利用して,DBColumnを返します。 122 * 123 * @og.rev 3.4.0.0 (2003/09/01) ラベルカラム、コードカラム、表示パラメータ、編集パラメータ、文字パラメータの追加。 124 * @og.rev 3.5.6.4 (2004/07/16) 追加パラメータ取り込み時に、"_" は、null 扱いとする。 125 * @og.rev 3.6.0.7 (2004/11/06) DBColumn の official属性追加 126 * 127 * @param key カラムID 128 * 129 * @return DBColumnオブジェクト 130 */ 131 public DBColumn getDBColumn( final String key ) { 132 DBColumn clm = columnPool.get( key ); 133 if( clm == null ) { 134 ColumnData clmDt = columnLoader.getColumnData( key ); 135 if( clmDt != null ) { 136 String label_clm = clmDt.getLabelColumn(); 137 String code_clm = clmDt.getCodeColumn(); 138 139 clm = new DBColumn( 140 lang, 141 clmDt, 142 labelLoader.getLabelData( label_clm ), 143 codeLoader.getCodeData( code_clm ) ); 144 145 columnPool.put( key,clm ); 146 } 147 } 148 return clm; 149 } 150 151 /** 152 * DBColumn オブジェクトを作成します。 153 * 内部にプールに存在すればそれを、なければ新規に作成します。 154 * それでも存在しない場合は、DBColumnConfig より、ラベルと言語を指定して 155 * 新規に作成します。 156 * 157 * @param key カラムID 158 * 159 * @return DBColumnオブジェクト 160 * @see #getDBColumn( String ) 161 */ 162 public DBColumn makeDBColumn( final String key ) { 163 DBColumn dbColumn = getDBColumn( key ); 164 if( dbColumn == null ) { 165 DBColumnConfig config = new DBColumnConfig( key ); 166 config.setLabelData( getLabelData( key ) ); 167 config.setLang( getLang() ); 168 dbColumn = new DBColumn( config ); 169 } 170 return dbColumn; 171 } 172 173 /** 174 * DBColumn オブジェクトをプールに登録します。 175 * DBColumn を動的に作成する機能で、作成したカラムオブジェクトを 176 * プールに登録することで、通常のリソースと同じように利用できるように 177 * します。 178 * 179 * @og.rev 5.4.2.2 (2011/12/14) 新規追加 180 * 181 * @param key カラムID 182 * @param dbColumn DBColumnオブジェクト 183 */ 184 public void setDBColumn( final String key , final DBColumn dbColumn ) { 185 if( key != null && key.length() > 0 && dbColumn != null ) { 186 columnPool.put( key,dbColumn ); 187 } 188 } 189 190 /** 191 * ラベルリソースから,ラベルを返します。 192 * 引数の言語コードに応じたリソースが登録されていない場合は, 193 * 引数のラベルキーそのまま返します。 194 * 195 * @og.rev 4.0.0.0 (2005/01/31) オラクルとWindowsとの間の "~"の文字化け対策中止 196 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソースとの統合化 197 * 198 * @param key ラベルキー 199 * 200 * @return リソースに応じたラベル文字列(無ければ ラベルキー) 201 */ 202 public String getLabel( final String key ) { 203 LabelData lblData = labelLoader.getLabelData( key ); 204 if( lblData != null ) { 205 String rtn = lblData.getLabel(); 206 if( rtn != null ) { 207 return rtn; 208 } 209 } 210 211 // なければ key を返す 212 return key; 213 } 214 215 /** 216 * メッセージリソースから,キーで指定されたメッセージに, 217 * 引数で指定された変数値をセットしたメッセージを返します。 218 * 219 * このメッセージは,リソースで選ばれたロケール毎のメッセージに, 220 * MessageFormat#format でフォーマットする事により,作成されます。 221 * メッセージがリソースに存在しない場合は,キーを返します。 222 * 223 * @og.rev 4.0.0.0 (2005/01/31) オラクルとWindowsとの間の "~"の文字化け対策 224 * @og.rev 4.0.0.0 (2007/10/17) メッセージリソース統合に伴いラベルローダーを使用する 225 * @og.rev 4.0.0.0 (2007/10/18) 名称変更 getMessage ⇒ getLabel 226 * @og.rev 5.1.1.0 (2009/12/01) #xxxxの変換で、カラム名が複数指定されている場合の対応 227 * 228 * @param key キー 229 * @param args メッセージの引数 230 * 231 * @return メッセージ(無ければ キー) 232 */ 233 public String getLabel( final String key,final String[] args ) { 234 final String msglbl ; 235 236 if( args == null ) { 237 msglbl = getLabel( key ); 238 } 239 else { 240 LabelData msgDt = labelLoader.getLabelData( key ); 241 242 int size = args.length; 243 String[] msgArgs = new String[size]; 244 for( int i=0; i<size; i++ ) { 245 String arg = args[i] ; 246 if( arg != null && arg.startsWith( "#" ) ) { 247 if( arg.indexOf( ',' ) < 0 ) { 248 msgArgs[i] = getLabel( arg.substring( 1 ) ); 249 } 250 // 5.1.1.0 (2009/12/01) #CLM,LANG,KBSAKU 等項目名が複数指定できるようにする 251 else { 252 String[] argArr = StringUtil.csv2Array( arg.substring( 1 ) ); 253 StringBuilder argBuf = new StringBuilder(); 254 for( int j=0; j<argArr.length; j++ ) { 255 if( j > 0 ) { 256 argBuf.append( ',' ); 257 } 258 argBuf.append( getLabel( argArr[j]) ); 259 } 260 msgArgs[i] = getLabel( argBuf.toString() ); 261 } 262 } 263 else { 264 msgArgs[i] = arg ; 265 } 266 } 267 268 msglbl = msgDt.getMessage( msgArgs ); 269 } 270 271 return msglbl; 272 } 273 274 /** 275 * メッセージリソースから,ErrMsgオブジェクトで指定されたメッセージを返します。 276 * 277 * このエラーメッセージは,リソースで選ばれたロケール毎のメッセージに, 278 * MessageFormat#format でフォーマットする事により,作成されます。 279 * エラーメッセージがリソースに存在しない場合は,エラーコードを返します。 280 * 281 * @og.rev 4.0.0.0 (2004/12/31) 新規追加 282 * @og.rev 4.0.0.0 (2007/10/18) メッセージリソースとの統合化 283 * 284 * @param errMsg ErrMsgオブジェクト 285 * 286 * @return エラーメッセージ(無ければ ErrMsgオブジェクトの toString() ) 287 */ 288 public String getLabel( final ErrMsg errMsg ) { 289 String key = errMsg.getId(); 290 String[] args = errMsg.getArgs(); 291 292 return getLabel( key,args ); 293 } 294 295 /** 296 * ラベルリソースから,ラベル(短)を返します。 297 * 引数の言語コードに応じたリソースが登録されていない場合は, 298 * 引数のラベルキーそのまま返します。 299 * 300 * @og.rev 4.3.3.0 (2008/10/01) 新規作成 301 * 302 * @param key ラベルキー 303 * 304 * @return リソースに応じたラベル文字列(無ければ ラベルキー) 305 */ 306 public String getShortLabel( final String key ) { 307 LabelData lblData = labelLoader.getLabelData( key ); 308 if( lblData != null ) { 309 String rtn = lblData.getShortLabel(); 310 if( rtn != null ) { 311 return rtn; 312 } 313 } 314 315 // なければ key を返す 316 return key; 317 } 318 319 /** 320 * ラベルリソースから,概要説明を返します。 321 * キーのデータが存在しない場合はnullを返します。 322 * 323 * @og.rev 4.3.4.5 (2009/01/08) 新規作成 324 * 325 * @param key ラベルキー 326 * 327 * @return リソースに応じた概要説明(無ければ null) 328 */ 329 public String getDescription( final String key ) { 330 LabelData lblData = labelLoader.getLabelData( key ); 331 if( lblData != null ) { 332 String rtn = lblData.getDescription(); 333 if( rtn != null ) { 334 return rtn; 335 } 336 } 337 // キーが存在しなければnullで返す 338 return null; 339 } 340 341 /** 342 * ラベルリソースから,概要説明を返します。 343 * {0},{1}...の置換えを行います。 344 * キーのデータが存在しない場合はnullを返します。 345 * 346 * @og.rev 4.3.7.6 (2009/07/15) 新規作成 347 * 348 * @param key ラベルキー 349 * @param args パラメータ 350 * 351 * @return リソースに応じた概要説明(無ければ null) 352 */ 353 public String getDescription( final String key, final String[] args ) { 354 String rtn = null; 355 if( args == null ){ 356 rtn = getDescription( key ); 357 } 358 else{ 359 LabelData lblData = labelLoader.getLabelData( key ); 360 if( lblData != null ) { 361 int size = args.length; 362 String[] msgArgs = new String[size]; 363 for( int i=0; i<size; i++ ) { 364 String arg = args[i] ; 365 if( arg != null && arg.startsWith( "#" ) ) { 366 msgArgs[i] = getLabel( arg.substring( 1 ) ); 367 } 368 else { 369 msgArgs[i] = arg ; 370 } 371 } 372 rtn = lblData.getDescription( msgArgs ); 373 } 374 } 375 // キーが存在しなければnullで返る 376 return rtn; 377 } 378 379 /** 380 * ラベルリソースから,概要説明を返します。 381 * キーのデータが存在しない場合はnullを返します。 382 * 383 * @og.rev 4.3.7.6 (2009/07/15) 新規作成 384 * 385 * @param errMsg ErrMsgオブジェクト 386 * 387 * @return エラーメッセージ(キーが無ければnull) 388 */ 389 public String getDescription( final ErrMsg errMsg ) { 390 String key = errMsg.getId(); 391 String[] args = errMsg.getArgs(); 392 393 return getDescription( key,args ); 394 } 395 396 /** 397 * ラベルリソースから,ラベルを返します。 398 * 引数の言語コードに応じたリソースが登録されていない場合は, 399 * 引数のラベルキーそのまま返します。 400 * 401 * @og.rev 4.0.0.0 (2005/01/31) 新規作成 402 * 403 * @param key ラベルキー 404 * 405 * @return リソースに応じたラベル文字列(無ければ ラベルキー) 406 */ 407 public LabelData getLabelData( final String key ) { 408 return labelLoader.getLabelData( key ); 409 } 410 411 /** 412 * コードリソースから,コード文字列を返します。 413 * 414 * @param key コードキー 415 * 416 * @return コードデータオブジェクト(無ければ null) 417 */ 418 public CodeData getCodeData( final String key ) { 419 return codeLoader.getCodeData( key ); 420 } 421 422 /** 423 * コードリソースから,コード文字列を返します。 424 * 引数にQUERYを渡すことで、DBから、動的にコードリソースを作成できます。 425 * 426 * @og.rev 5.4.2.2 (2011/12/14) 新規追加。 427 * 428 * @param key コードキー 429 * @param query 検索SQL(引数に、? を一つ持つ) 430 * 431 * @return コードデータオブジェクト(無ければ null) 432 */ 433 public CodeData getCodeData( final String key,final String query ) { 434 return codeLoader.getCodeData( key,query ); 435 } 436 437 /** 438 * ログインユーザーで使用する画面オブジェクトを、UserInfoにセットします。 439 * 各、UserInfo は、自分自身が使用する 画面オブジェクトのみを管理することで、 440 * 画面アクセス有無を、すばやく検索することが可能になります。 441 * 442 * @og.rev 3.1.0.1 (2003/03/26) GUIInfo のキー順サポートの為に、引数追加。 443 * @og.rev 4.0.0.0 (2005/01/31) 使用画面のMap を UserInfo にセットします。 444 * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応 445 * @og.rev 5.2.0.0 (2010/09/01) アクセス禁止アドレスによる不正アクセス防止機能追加 446 * 447 * @param user 指定のユーザーロールに対応する画面だけをMapにセットする。 448 */ 449 public void makeGUIInfos( final UserInfo user ) { 450 GUIData[] guiDatas = guiLoader.getAllData(); 451 452 // guikey に対してユニークになるように Map に追加します。後登録が優先されます。 453 Map<String,GUIInfo> guiMap = new HashMap<String,GUIInfo>(); 454 Set<String> forbidAddrSet = new HashSet<String>(); 455 int size = guiDatas.length; 456 for( int i=0; i<size; i++ ) { 457 GUIData gui = guiDatas[i]; 458 byte bitMode = user.getAccessBitMode( gui.getRoleMode() ); 459 if( bitMode > 0 ) { 460 String guikey = gui.getGuiKey(); 461 LabelData labelData = getLabelData( gui.getLabelClm() ); 462 guiMap.put( guikey,new GUIInfo( gui,labelData,bitMode ) ); 463 } 464 // 5.2.0.0 (2010/09/01) アクセス禁止アドレスによる不正アクセス防止機能追加 465 else { 466 String addr = gui.getAddress(); 467 if( addr.indexOf( '/' ) < 0 ) { 468 forbidAddrSet.add( addr ); 469 } 470 } 471 } 472 473 // もし、禁止リストの中に画面ID違いで許可リストと同じアドレスが 474 // 含まれている場合は、禁止リスト中から該当のアドレスを削除する。 475 for( GUIInfo gui : guiMap.values() ) { 476 String addr = gui.getAddress(); 477 if( forbidAddrSet.contains( gui.getAddress() ) ) { 478 forbidAddrSet.remove( addr ); 479 } 480 } 481 482 // GUIInfo をその順番(SEQNO順)でソートし直します。 483 GUIInfo[] guiInfos = guiMap.values().toArray( new GUIInfo[ guiMap.size() ] ) ; 484 Arrays.sort( guiInfos ); 485 Map<String,GUIInfo> sortMap = new LinkedHashMap<String,GUIInfo>(); 486 size = guiInfos.length; 487 for( int i=0; i<size; i++ ) { 488 GUIInfo guiInfo = guiInfos[i]; 489 String guikey = guiInfo.getKey(); 490 sortMap.put( guikey,guiInfo ); 491 } 492 493 user.setGUIMap( sortMap, forbidAddrSet ); 494 } 495 496 /** 497 * 指定されたクエリを発行し、ラベルマップを作成します。 498 * 499 * @og.rev 4.3.4.0 (2008/12/01) 新規作成 500 * 501 * @param query ラベルマップを作成するクエリ 502 * 503 * @return ラベルマップ 504 * @see org.opengion.hayabusa.resource.LabelDataLoader#getLabelMap( String ) 505 */ 506 public Map<String, LabelData> getLabelMap( final String query ) { 507 return labelLoader.getLabelMap( query ); 508 } 509 510 /** 511 * リソースマネージャーをキーに基づいて部分クリアします。 512 * ここでは、部分クリアなため、GUIData に関しては、処理されません。 513 * また、存在しないキーを指定されたリソースは、何も処理されません。 514 * 515 * @og.rev 5.4.3.4 (2012/01/12) labelPool の削除追加 516 * 517 * @param key カラムのキー 518 */ 519 public void clear( final String key ) { 520 System.out.println( "Key=[" + key + "] の部分リソースクリアを実施しました。" ); 521 columnLoader.clear( key ); 522 codeLoader.clear( key ); 523 labelLoader.clear( key ); 524 columnPool.remove( key ); 525 } 526 527 /** 528 * GUI情報をクリアします。 529 * ここでは、関連するラベル、コードリソースの部分クリアも行います。 530 * GUI情報は、シーケンスに管理しているため、この処理1回ごとに、 531 * GUIData を全件再読み込みを行いますので、ご注意ください。 532 * 533 */ 534 public void guiClear() { 535 GUIData[] gui = guiLoader.getAllData(); 536 537 for( int i=0; i<gui.length; i++ ) { 538 String key = gui[i].getGuiKey(); 539 labelLoader.clear( key ); 540 } 541 codeLoader.clear( "CLASSIFY" ); 542 guiLoader.clear(); 543 } 544 545 /** 546 * リソースマネージャーをクリア(初期化)します。 547 * 548 * @og.rev 5.4.3.4 (2012/01/12) labelPool の削除追加 549 * 550 */ 551 public void clear() { 552 columnLoader.clear(); 553 codeLoader.clear(); 554 labelLoader.clear(); 555 guiLoader.clear(); 556 columnPool.clear(); 557 } 558}