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.HashMap;
020import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
021import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
022import java.util.HashSet;
023import java.util.LinkedHashMap;
024import java.util.Map;
025import java.util.Set;
026
027import java.util.stream.Stream;                                                                         // 6.4.1.1 (2016/01/16)
028import java.util.stream.Collectors;                                                                     // 6.4.1.1 (2016/01/16)
029
030import org.opengion.fukurou.util.ErrMsg;
031import org.opengion.fukurou.util.StringUtil;
032import org.opengion.hayabusa.db.DBColumn;
033import org.opengion.hayabusa.db.DBColumnConfig;
034import static org.opengion.fukurou.system.HybsConst.BUFFER_LARGE;               // 6.1.0.0 (2014/12/26) refactoring
035import org.opengion.hayabusa.common.HybsSystemException;                                // 6.4.3.3 (2016/03/04)
036
037/**
038 * java.util.ResourceBundle クラスを複数管理するリソースクラスです。
039 *
040 * ResourceManager は、
041 *      LabelResource.properties   ラベルリソース(テーブル定義やカラム名などの画面に表示するリソース)
042 *      CodeResource.properties    コードリソース(選択データなどプルダウンメニューで選択するリソース)
043 *      MessageResource.properties メッセージリソース(エラーコードやメッセージなどを表示するリソース)
044 *
045 * の3つのプロパティーファイルを内部に持っており,それぞれのメソッドにより,
046 * リソースの返す値を決めています。
047 *
048 * ResourceManagerは,単独でも生成できますが,各ユーザー毎に作成するよりも
049 * ResourceFactory#newInstance( lang )メソッドより生成した方が,プーリングされるので
050 * 効率的です。
051 *
052 * リソース作成時に指定するロケールは,ISO 言語コード(ISO-639 で定義される 2 桁の小文字)
053 * <a href ="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">
054 * http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt</a>を使用して下さい。
055 * ただし,内部的に Locale を構築していますが,その正しさは,チェックされていませんので,
056 * 指定するロケールに応じた properties ファイルを用意しておいて下さい。
057 *
058 * 日本語の場合は, 言語コードは "jp" なので,
059 *      LabelResource_jp.properties   ラベルリソース(日本語)
060 *      CodeResource_jp.properties    コードリソース(日本語)
061 *      MessageResource_jp.properties メッセージリソース(日本語)
062 *
063 * を用意して下さい。
064 *
065 * CodeResource については、リソースファイルから CodeSelectionオブジェクトを
066 * 作成して利用します。この、CodeSelectionオブジェクトの作成方法として、
067 * 3通り考えられます。
068 * 1つ目は、毎回 要求が発生する毎に CodeSelection を作成し、プールしていきます。こうすることで、
069 * 初めて使用されたときだけオブジェクト化されますので、メモリの節約が可能です。ただし、
070 * プールにヒットしなかった場合は、やはりリソースから検索しますので、元々ヒットしない
071 * キーに対しては、毎回リソースを検索するため、非効率です。
072 * 2つめは、元々ヒットしないキーに対して、NullCodeSelectionオブジェクトを登録しておくことで、
073 * プールにため込んで行くと言う方法です。この場合は、シングルトーンにしてメモリを節約しますが、
074 * それでもプール自体の容量は、確保しておく必要があります。
075 * 3つめは、この ResourceManager がインスタンス化されるときに、すべての CodeSelectionオブジェクトを
076 * あらかじめ プールしておく方法です。使わない CodeSelection もインスタンス化する変わりに、
077 * キャッシュにヒットしない場合は、即 CodeSelection が存在しないと判断できるため、
078 * もっともパフォーマンスが高くなります。
079 * 本 ResourceManager の実装は、3つめの、あらかじめ、すべてをキャッシュしておく方法を
080 * 採用しています。
081 *
082 * @og.group リソース管理
083 *
084 * @version  4.0
085 * @author       Kazuhiko Hasegawa
086 * @since    JDK5.0,
087 */
088public final class ResourceManager {
089        private final ColumnDataLoader  columnLoader ;
090        private final CodeDataLoader    codeLoader;
091        private final LabelDataLoader   labelLoader;
092        private final GUIDataLoader             guiLoader;
093
094        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
095        private final ConcurrentMap<String,DBColumn> columnPool = new ConcurrentHashMap<>( BUFFER_LARGE );
096        private final String    lang ;
097
098        /**
099         *      コンストラクター
100         *      システムIDと言語コードを指定して,生成します。
101         *
102         * @param       systemId システムID
103         * @param       lg 言語コード
104         * @param       initLoad リソースデータの先読み可否(true:先読みする)
105         */
106        public ResourceManager( final String systemId,final String lg,final boolean initLoad ) {
107                this.lang               = lg;
108
109                columnLoader    = new ColumnDataLoader( systemId,initLoad );
110                labelLoader             = new LabelDataLoader( systemId,lang,initLoad );
111                codeLoader              = new CodeDataLoader( systemId,initLoad,labelLoader ); // 4.0.0.0(2007/10/17)
112                guiLoader               = new GUIDataLoader( systemId );
113        }
114
115        /**
116         * 設定されている言語を返します。
117         *
118         * @return      言語
119         */
120        public String getLang() {
121                return lang;
122        }
123
124        /**
125         * DBColumn オブジェクトを取得します。
126         * 作成したDBColumnオブジェクトは,内部にプールしておき,同じオブジェクト要求が
127         * あったときは,プールのオブジェクトを利用して,DBColumnを返します。
128         *
129         * @og.rev 3.4.0.0 (2003/09/01) ラベルカラム、コードカラム、表示パラメータ、編集パラメータ、文字パラメータの追加。
130         * @og.rev 3.5.6.4 (2004/07/16) 追加パラメータ取り込み時に、"_" は、null 扱いとする。
131         * @og.rev 3.6.0.7 (2004/11/06) DBColumn の official属性追加
132         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
133         *
134         * @param       key     カラムID(not null)
135         *
136         * @return      DBColumnオブジェクト
137         */
138        public DBColumn getDBColumn( final String key ) {
139                // 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
140                if( key == null ) {
141                        final String errMsg = "カラムIDに、NULL は指定できません。";
142                        throw new HybsSystemException( errMsg );
143                }
144
145                DBColumn clm = columnPool.get( key );
146                if( clm == null ) {
147                        final ColumnData clmDt = columnLoader.getColumnData( key );
148                        if( clmDt != null ) {
149                                final String label_clm = clmDt.getLabelColumn();
150                                final String code_clm  = clmDt.getCodeColumn();
151
152                                clm = new DBColumn(
153                                                        lang,
154                                                        clmDt,
155                                                        labelLoader.getLabelData( label_clm ),
156                                                        codeLoader.getCodeData( code_clm ) );
157
158                                columnPool.put( key,clm );
159                        }
160                }
161                return clm;
162        }
163
164        /**
165         * DBColumn オブジェクトを作成します。
166         * 内部にプールに存在すればそれを、なければ新規に作成します。
167         * それでも存在しない場合は、DBColumnConfig より、ラベルと言語を指定して
168         * 新規に作成します。
169         *
170         * @param       key             カラムID(not null)
171         *
172         * @og.rev 7.1.0.0 (2020/01/27) LabelDataを直接呼び出します。
173         *
174         * @return      DBColumnオブジェクト
175         * @see         #getDBColumn( String )
176         */
177        public DBColumn makeDBColumn( final String key ) {
178                DBColumn dbColumn = getDBColumn( key );
179                if( dbColumn == null ) {
180                        final DBColumnConfig config = new DBColumnConfig( key );
181                        config.setLabelData( labelLoader.getLabelData( key ) );         // 7.1.0.0 (2020/01/27)
182//                      config.setLabelData( getLabelData( key ) );
183//                      config.setLang( getLang() );
184                        config.setLang( lang );
185                        dbColumn = new DBColumn( config );
186                }
187                return dbColumn;
188        }
189
190        /**
191         * DBColumn オブジェクトを作成します。
192         * 内部にプールに存在すればそれを、なければ新規に作成します。
193         * それでも存在しない場合は、DBColumnConfig より、ラベルと言語を指定して
194         * 新規に作成します。
195         * lbl引数が、nullか、ゼロ文字列の場合は、#makeDBColumn(String) と同じです。
196         *
197         * @og.rev 6.9.1.0 (2018/02/26) unionLbls追加
198         * @og.rev 7.1.0.0 (2020/01/27) LabelDataを直接呼び出します。
199         *
200         * @param       key     カラムID(not null)
201         * @param       lbl     ラベル(nullか、ゼロ文字列の場合は、設定しません)
202         *
203         * @return      DBColumnオブジェクト
204         * @see         #getDBColumn( String )
205         */
206        public DBColumn makeDBColumn( final String key , final String lbl ) {
207                if( lbl == null || lbl.isEmpty() ) { return makeDBColumn( key ); }
208
209                final DBColumn dbColumn = getDBColumn( key );
210                final DBColumnConfig config ;
211
212                if( dbColumn == null ) {
213                        config = new DBColumnConfig( key );
214//                      config.setLang( getLang() );
215                        config.setLang( lang );
216                }
217                else {
218                        config = dbColumn.getConfig();
219                }
220
221//              config.setLabelData( getLabelData( lbl ) );
222                config.setLabelData( labelLoader.getLabelData( lbl ) );         // 7.1.0.0 (2020/01/27)
223
224                return new DBColumn( config );
225        }
226
227//      /**
228//       * DBColumn オブジェクトをプールに登録します。
229//       * DBColumn を動的に作成する機能で、作成したカラムオブジェクトを
230//       * プールに登録することで、通常のリソースと同じように利用できるように
231//       * します。
232//       *
233//       * @og.rev 5.4.2.2 (2011/12/14) 新規追加
234//       * @og.rev 7.1.0.0 (2020/01/27) Editor_ENTCLM 廃止に伴い、メソッド削除
235//       *
236//       * @param       key  カラムID
237//       * @param       dbColumn DBColumnオブジェクト
238//       */
239//      public void setDBColumn( final String key , final DBColumn dbColumn ) {
240//              if( key != null && key.length() > 0 && dbColumn != null ) {
241//                      columnPool.put( key,dbColumn );
242//              }
243//      }
244
245//      /**
246//       * ラベルリソースから,ラベルを返します。
247//       * 引数の言語コードに応じたリソースが登録されていない場合は,
248//       * 引数のラベルキーそのまま返します。
249//       *
250//       * @og.rev 4.0.0.0 (2005/01/31) オラクルとWindowsとの間の "~"の文字化け対策中止
251//       * @og.rev 4.0.0.0 (2007/10/18) メッセージリソースとの統合化
252//       * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
253//       * @og.rev 7.0.7.0 (2019/12/13) #getLabel( String,String... ) と統合します。
254//       *
255//       * @param       key ラベルキー
256//       *
257//       * @return      リソースに応じたラベル文字列(無ければ ラベルキー)
258//       */
259//      public String getLabel( final String key ) {
260//              final LabelData lblData = labelLoader.getLabelData( key );
261//              // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
262//              // 反転注意
263//              final String rtn = lblData.getLabel();
264//
265//              return rtn == null ? key : rtn ;                // なければ key を返す
266//      }
267
268        /**
269         * メッセージリソースから,キーで指定されたメッセージに,
270         * 引数で指定された変数値をセットしたメッセージを返します。
271         *
272         * このメッセージは,リソースで選ばれたロケール毎のメッセージに,
273         * MessageFormat#format でフォーマットする事により,作成されます。
274         * メッセージがリソースに存在しない場合は,キーを返します。
275         *
276         * @og.rev 4.0.0.0 (2005/01/31) オラクルとWindowsとの間の "~"の文字化け対策
277         * @og.rev 4.0.0.0 (2007/10/17) メッセージリソース統合に伴いラベルローダーを使用する
278         * @og.rev 4.0.0.0 (2007/10/18) 名称変更 getMessage ⇒ getLabel
279         * @og.rev 5.1.1.0 (2009/12/01) #XXXXの変換で、カラム名が複数指定されている場合の対応
280         * @og.rev 6.1.0.0 (2014/12/26) LabelData が存在しなかった場合の処理
281         * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
282         * @og.rev 6.6.0.0 (2016/12/01) 引数の配列を可変長配列に変更します。
283         * @og.rev 7.0.7.0 (2019/12/13) #getLabel( String ) と統合します。
284         *
285         * @param       key キー
286         * @param       args メッセージの配列
287         *
288         * @return      メッセージ(無ければ キー)
289         */
290        public String getLabel( final String key,final String... args ) {                       // 6.6.0.0 (2016/12/01)
291                final LabelData lblData = labelLoader.getLabelData( key );
292
293                final String msglbl ;
294
295                if( args == null || args.length == 0 ){
296//                      msglbl = getLabel( key );
297                        msglbl = lblData.getLabel();
298                }
299                else {
300                        // 6.1.0.0 (2014/12/26) メソッド化
301                        final String[] msgArgs = makeLabelArray( args );        // 6.1.0.0 (2014/12/26) メソッド化
302
303//                      // 6.1.0.0 (2014/12/26) LabelData が存在しなかった場合の処理
304//                      final LabelData lblData = labelLoader.getLabelData( key );
305                        // 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
306                        msglbl = lblData.getMessage( msgArgs );
307                }
308
309//              return msglbl;
310                return msglbl == null ? key : msglbl ;          // なければ key を返す
311        }
312
313        /**
314         * ラベルリソースから,ラベルを返します。
315         * ただし、キーに、「スペース+%+記号」を判定、処理する機能を用意します。
316         *
317         * 記号は、Label,Short,Tips,Description,RawShortLabel,CodeData の頭文字一つ目です。
318         * ('L','S','T','D','R','C') となります。
319         * 'L' は通常のラベルと同じ。'C' は、'S'(Short)と同じになります。
320         *
321         * 「スペース+%+記号」が無ければ、通常のラベルと同じ処理を行います。
322         * つまり、このメソッドは、getLabel(String) より、ほんの少し処理時間を稼ぐために用意しました。
323         * なので、一応、内部からしか呼ばない事とし、private にしておきます。
324         *
325         * @og.rev 6.3.8.4 (2015/10/09) XXXX %S などの対応。getLabel(String) は汎用過ぎるので、少し分ける。
326         * @og.rev 6.3.9.0 (2015/11/06) switch 文の2つの case のために同じコードを使用している(findbugs)
327         *
328         * @param       key ラベルキー
329         *
330         * @return      リソースに応じたラベル文字列(無ければ ラベルキー)
331         */
332        private String getExtLabel( final String key ) {
333                final String val ;
334
335                final int ad = key.indexOf( " %" );
336                if( ad < 0 ) {
337                        val = getLabel( key );
338                }
339                else if( ad+2 <= key.length() ) {               // " %" の後ろの文字が存在しない場合
340                        val = getLabel( key.substring( 0,ad ) );
341                }
342                else {
343                        final String tmpKey = key.substring( 0,ad );
344                        // 6.3.9.0 (2015/11/06) switch 文の2つの case のために同じコードを使用している(findbugs)
345                        switch( key.charAt( ad+2 ) ) {
346                                case 'L': val = getLabel(         tmpKey );     break;
347                                case 'S':
348                                case 'C': val = getShortLabel(    tmpKey );     break;  // 6.3.9.0 (2015/11/06) findbugs対応
349                                case 'T': val = getLongLabel(     tmpKey );     break;
350                                case 'D': val = getDescription(   tmpKey );     break;
351                                case 'R': val = getRawShortLabel( tmpKey );     break;
352                                default : val = getLabel(         tmpKey );     break;
353                        }
354                }
355                return val;
356        }
357
358        /**
359         * ラベルリソースの引数で、#XXXXの変換で、カラム名が複数指定されている場合の対応を行います。
360         *
361         * 一つの引数に、#CLM,LANG,KBSAKU 等の項目名が複数指定指定された場合に、
362         * それぞれを解析してラベルに戻します。
363         * 該当するラベルが存在しない場合は、そのままの値を返します。
364         * 返される文字列配列は、元の引数とは異なる新しい文字列配列で返されます。
365         *
366         * @og.rev 6.1.0.0 (2014/12/26) #XXXXの変換で、カラム名が複数指定されている場合の対応
367         * @og.rev 6.3.8.4 (2015/10/09) #XXXX %S などの対応。getLabel(String) は汎用過ぎるので、少し分ける。
368         * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. Java8 ラムダ式を使用して、大幅書き直し。
369         * @og.rev 7.0.4.2 (2019/06/17) # のみの場合は、特別に、# を返すように対応。
370         *
371         * @param       args メッセージの配列
372         *
373         * @return      ラベル置換後の新しい文字列配列
374         */
375        private String[] makeLabelArray( final String[] args ) {
376                final int size = args.length;
377                final String[] msgArgs = new String[size];
378
379                for( int i=0; i<size; i++ ) {
380                        final String arg = args[i] ;
381//                      if( StringUtil.startsChar( arg , '#' ) ) {
382                        if( StringUtil.startsChar( arg , '#' ) && arg.length() > 1 ) {                                  // 7.0.4.2 (2019/06/17)
383                                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid instantiating new objects inside loops
384                                msgArgs[i] = Stream.of( StringUtil.csv2Array( arg.substring( 1 ) ) )
385                                                                .map( lbl -> getExtLabel( lbl ) )
386                                                                .collect( Collectors.joining( "," ) );
387                        }
388                        else {
389                                msgArgs[i] = arg ;
390                        }
391                }
392                return msgArgs ;
393        }
394
395        /**
396         * ラベルリソースから,ラベル(短)を返します。
397         * 引数の言語コードに応じたリソースが登録されていない場合は,
398         * 引数のラベルキーそのまま返します。
399         *
400         * @og.rev 4.3.3.0 (2008/10/01) 新規作成
401         * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
402         *
403         * @param       key ラベルキー
404         *
405         * @return      リソースに応じたラベル文字列(無ければ ラベルキー)
406         */
407        public String getShortLabel( final String key ) {
408                final LabelData lblData = labelLoader.getLabelData( key );
409                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
410                // 反転注意
411                final String rtn = lblData.getShortLabel();
412
413                return rtn == null ? key : rtn ;                // なければ key を返す
414        }
415
416        /**
417         * ラベルリソースから,ラベル(長)を返します。
418         * 概要説明が存在する場合は、ツールチップに概要説明が
419         * 表示されます。
420         * 引数の言語コードに応じたリソースが登録されていない場合は,
421         * 引数のラベルキーそのまま返します。
422         *
423         * @og.rev 6.3.8.4 (2015/10/09) #XXXX %S などの対応。getLabel(String) は汎用過ぎるので、少し分ける。
424         * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
425         *
426         * @param       key ラベルキー
427         *
428         * @return      リソースに応じたラベル(長)文字列(無ければ ラベルキー)
429         */
430        public String getLongLabel( final String key ) {
431                final LabelData lblData = labelLoader.getLabelData( key );
432                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
433                // 反転注意
434                final String rtn = lblData.getLongLabel();
435
436                return rtn == null ? key : rtn ;                // なければ key を返す
437        }
438
439        /**
440         * ラベルオブジェクトの名称(短)をspanタグを付けない状態で返します。
441         * SNAMEが未設定の場合は、LNAME が返されます。
442         * 引数の言語コードに応じたリソースが登録されていない場合は,
443         * 引数のラベルキーそのまま返します。
444         *
445         * @og.rev 6.3.8.4 (2015/10/09) #XXXX %S などの対応。getLabel(String) は汎用過ぎるので、少し分ける。
446         * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
447         * @og.rev 7.0.7.0 (2019/12/13) args パラメータ配列(可変長引数)を追加します。
448         *
449         * @param       key ラベルキー
450         * @param       args パラメータ配列(可変長引数)
451         *
452         * @return      リソースに応じたラベル(長)文字列(無ければ ラベルキー)
453         */
454        public String getRawShortLabel( final String key,final String... args ) {
455                final LabelData lblData = labelLoader.getLabelData( key );
456
457                final String msglbl ;
458                if( args == null || args.length == 0 ){
459                        msglbl = lblData.getRawShortLabel();
460                }
461                else {
462                        // 6.1.0.0 (2014/12/26) メソッド化
463                        final String[] msgArgs = makeLabelArray( args );        // 6.1.0.0 (2014/12/26) メソッド化
464
465                        // 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
466                        msglbl = lblData.getShortMessage( msgArgs );
467                }
468
469                return msglbl == null ? key : msglbl ;          // なければ key を返す
470        }
471//      public String getRawShortLabel( final String key ) {
472//              final LabelData lblData = labelLoader.getLabelData( key );
473//              // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
474//              // 反転注意
475//              final String rtn = lblData.getRawShortLabel();
476//
477//              return rtn == null ? key : rtn ;                // なければ key を返す
478//      }
479
480//      /**
481//       * ラベルリソースから,概要説明を返します。
482//       * キーのデータが存在しない場合はnullを返します。
483//       *
484//       * @og.rev 4.3.4.5 (2009/01/08) 新規作成
485//       * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
486//       * @og.rev 7.0.7.0 (2019/12/13) #getDescription( String ) と統合します。
487//       *
488//       * @param       key ラベルキー
489//       *
490//       * @return      リソースに応じた概要説明(無ければ null)
491//       */
492//      public String getDescription( final String key ) {
493//              final LabelData lblData = labelLoader.getLabelData( key );
494//
495//              // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
496//              return lblData.getDescription();        // キーが存在しなければnullで返す
497//      }
498
499        /**
500         * ラベルリソースから,概要説明を返します。
501         * {0},{1}...の置換えを行います。
502         * キーのデータが存在しない場合はnullを返します。
503         * ただし、パラメータのデータがあれば、それを返します。
504         *
505         * @og.rev 4.3.7.6 (2009/07/15) 新規作成
506         * @og.rev 6.1.0.0 (2014/12/26) #XXXXの変換で、カラム名が複数指定されている場合の対応
507         * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
508         * @og.rev 7.0.7.0 (2019/12/13) #getDescription( String ) と統合します。
509         *
510         * @param       key ラベルキー
511         * @param       args パラメータ配列(可変長引数)
512         *
513         * @return      リソースに応じた概要説明(無ければ null)
514         */
515//      public String getDescription( final String key, final String[] args ) {
516        public String getDescription( final String key,final String... args ) {                 // 6.6.0.0 (2016/12/01)
517                final LabelData lblData = labelLoader.getLabelData( key );
518
519                final String msgdesc ;
520                if( args == null || args.length == 0 ){
521//                      msgdesc = getDescription( key );
522                        msgdesc = lblData.getDescription();
523                }
524                else {
525                        // 6.1.0.0 (2014/12/26) getLabel( String ,String[] ) と同様に複数ラベル対応
526                        final String[] msgArgs = makeLabelArray( args );
527
528//                      // 6.1.0.0 (2014/12/26) LabelData が存在しなかった場合の処理
529//                      final LabelData lblData = labelLoader.getLabelData( key );
530                        msgdesc = lblData.getDescription( msgArgs );
531                }
532
533//              return msgdesc ;
534                return msgdesc == null ? key : msgdesc ;                // なければ key を返す
535        }
536
537        /**
538         * メッセージリソースから,ErrMsgオブジェクトで指定されたメッセージを返します。
539         *
540         * このエラーメッセージは,リソースで選ばれたロケール毎のメッセージに,
541         * MessageFormat#format でフォーマットする事により,作成されます。
542         * エラーメッセージがリソースに存在しない場合は,エラーコードを返します。
543         *
544         * @og.rev 4.0.0.0 (2004/12/31) 新規追加
545         * @og.rev 4.0.0.0 (2007/10/18) メッセージリソースとの統合化
546         *
547         * @param       errMsgObj ErrMsgオブジェクト
548         *
549         * @return      エラーメッセージ(無ければ ErrMsgオブジェクトの toString() )
550         */
551        public String getLabel( final ErrMsg errMsgObj ) {
552                return getLabel( errMsgObj.getId(),errMsgObj.getArgs() );
553        }
554
555        /**
556         * メッセージリソースから,ErrMsgオブジェクトで指定されたショートメッセージを返します。
557         *
558         * このエラーメッセージは,リソースで選ばれたロケール毎のメッセージに,
559         * MessageFormat#format でフォーマットする事により,作成されます。
560         * エラーメッセージがリソースに存在しない場合は,エラーコードを返します。
561         *
562         * @og.rev 7.0.7.0 (2019/12/13) 新規追加
563         *
564         * @param       errMsgObj ErrMsgオブジェクト
565         *
566         * @return      エラーメッセージ(無ければ ErrMsgオブジェクトの toString() )
567         */
568        public String getRawShortLabel( final ErrMsg errMsgObj ) {
569                return getRawShortLabel( errMsgObj.getId(),errMsgObj.getArgs() );
570        }
571
572        /**
573         * ErrMsgオブジェクトの内容を元に、ラベルリソースから,概要説明を返します。
574         * キーのデータが存在しない場合はnullを返します。
575         *
576         * @og.rev 4.3.7.6 (2009/07/15) 新規作成
577         *
578         * @param       errMsgObj ErrMsgオブジェクト
579         *
580         * @return      エラーメッセージ(キーが無ければnull)
581         */
582        public String getDescription( final ErrMsg errMsgObj ) {
583                return getDescription( errMsgObj.getId(),errMsgObj.getArgs() );
584        }
585
586        /**
587         * ラベルキーに対応する、LabelDataオブジェクトを返します。
588         *
589         * @og.rev 4.0.0.0 (2005/01/31) 新規作成
590         * @og.rev 6.3.9.0 (2015/11/06) labelLoader.getLabelDataは、nullを返しません。
591         *
592         * @param       key ラベルキー
593         *
594         * @return      LabelDataオブジェクト
595         * @og.rtnNotNull
596         */
597        public LabelData getLabelData( final String key ) {
598                return labelLoader.getLabelData( key );
599        }
600
601        /**
602         * コードキーに対応する、CodeDataオブジェクトを返します。
603         *
604         * @param       key コードキー
605         *
606         * @return      CodeDataオブジェクト(無ければ null)
607         */
608        public CodeData getCodeData( final String key ) {
609                return codeLoader.getCodeData( key );
610        }
611
612        /**
613         * コードリソースから,コード文字列を返します。
614         * 引数にQUERYを渡すことで、DBから、動的にコードリソースを作成できます。
615         *
616         * @og.rev 5.4.2.2 (2011/12/14) 新規追加。
617         *
618         * @param       key コードキー
619         * @param       query 検索SQL(引数に、? を一つ持つ)
620         *
621         * @return      コードデータオブジェクト(無ければ null)
622         */
623        public CodeData getCodeData( final String key,final String query ) {
624                return codeLoader.getCodeData( key,query );
625        }
626
627        /**
628         * ログインユーザーで使用する画面オブジェクトを、UserInfoにセットします。
629         * 各、UserInfo は、自分自身が使用する 画面オブジェクトのみを管理することで、
630         * 画面アクセス有無を、すばやく検索することが可能になります。
631         *
632         * @og.rev 3.1.0.1 (2003/03/26) GUIInfo のキー順サポートの為に、引数追加。
633         * @og.rev 4.0.0.0 (2005/01/31) 使用画面のMap を UserInfo にセットします。
634         * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
635         * @og.rev 5.2.0.0 (2010/09/01) アクセス禁止アドレスによる不正アクセス防止機能追加
636         * @og.rev 6.4.3.4 (2016/03/11) forループを、removeAll メソッドに置き換えます。
637         * @og.rev 6.4.4.2 (2016/04/01) guiMap.values() では、GUIInfo だが、remove するのは、gui.getAddress() の値。
638         * @og.rev 7.1.0.0 (2020/01/27) LabelDataを直接呼び出します。
639         *
640         * @param       user    指定のユーザーロールに対応する画面だけをMapにセットする。
641         */
642        public void makeGUIInfos( final UserInfo user ) {
643                final GUIData[] guiDatas = guiLoader.getAllData();
644
645                // guikey に対してユニークになるように Map に追加します。後登録が優先されます。
646                final Map<String,GUIInfo> guiMap = new HashMap<>();
647                final Set<String> forbidAddrSet  = new HashSet<>();
648                int size = guiDatas.length;
649                for( int i=0; i<size; i++ ) {
650                        final GUIData gui = guiDatas[i];
651                        final byte bitMode = user.getAccessBitMode( gui.getRoleMode() );
652                        if(  bitMode > 0 ) {
653                                final String      guikey        = gui.getGuiKey();
654//                              final LabelData labelData       = getLabelData( gui.getLabelClm() );
655                                final LabelData labelData       = labelLoader.getLabelData( gui.getLabelClm() );        // 7.1.0.0 (2020/01/27)
656                                guiMap.put( guikey,new GUIInfo( gui,labelData,bitMode ) );
657                        }
658                        // 5.2.0.0 (2010/09/01) アクセス禁止アドレスによる不正アクセス防止機能追加
659                        else {
660                                final String addr = gui.getAddress();
661                                if( addr.indexOf( '/' ) < 0 ) {
662                                        forbidAddrSet.add( addr );
663                                }
664                        }
665                }
666
667                // もし、禁止リストの中に画面ID違いで許可リストと同じアドレスが
668                // 含まれている場合は、禁止リスト中から該当のアドレスを削除する。
669                // 6.4.3.4 (2016/03/11) forループを、removeAll メソッドに置き換えます。
670                // 6.4.4.2 (2016/04/01) guiMap.values() では、GUIInfo だが、remove するのは、gui.getAddress() の値。
671                guiMap.forEach( (id,gui) -> forbidAddrSet.remove( gui.getAddress() ) );
672
673                // GUIInfo をその順番(SEQNO順)でソートし直します。SYSTEM_ID や、KBSAKU の影響を排除します。
674                final GUIInfo[] guiInfos = guiMap.values().toArray( new GUIInfo[ guiMap.size() ] ) ;
675                Arrays.sort( guiInfos );
676                final Map<String,GUIInfo> sortMap = new LinkedHashMap<>();
677                size = guiInfos.length;
678                for( int i=0; i<size; i++ ) {
679                        final GUIInfo guiInfo = guiInfos[i];
680                        final String guikey     = guiInfo.getKey();
681                        sortMap.put( guikey,guiInfo );
682                }
683
684                user.setGUIMap( sortMap, forbidAddrSet );
685        }
686
687        /**
688         * 指定されたクエリを発行し、ラベルマップを作成します。
689         *
690         * @og.rev 4.3.4.0 (2008/12/01) 新規作成
691         * @og.rev 6.4.0.5 (2016/01/09) useLabelMap="true" 時のSQL文の実行は、dbid を使用して行う。
692         *
693         * @param       query   ラベルマップを作成するクエリ
694         * @param       dbid    接続先ID
695         *
696         * @return      ラベルマップ
697         * @see org.opengion.hayabusa.resource.LabelDataLoader#getLabelMap( String,String )
698         */
699        public Map<String, LabelData> getLabelMap( final String query , final String dbid ) {
700                return labelLoader.getLabelMap( query , dbid );
701        }
702
703        /**
704         * リソースマネージャーをキーに基づいて部分クリアします。
705         * ここでは、部分クリアなため、GUIData に関しては、処理されません。
706         * また、存在しないキーを指定されたリソースは、何も処理されません。
707         *
708         * @og.rev 5.4.3.4 (2012/01/12) labelPool の削除追加
709         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加
710         * @og.rev 6.9.0.1 (2018/02/05) どのシステムIDのリソースがクリアされたかを表示します。
711         *
712         * @param   key         カラムのキー
713         */
714        public void clear( final String key ) {
715                // 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限
716                if( key != null ) {
717//                      System.out.println( "Key=[" + key + "] の部分リソースクリアを実施しました。" );   // 6.9.0.1 (2018/02/05) columnLoader へ移動
718                        columnLoader.clear( key );
719                        codeLoader.clear( key );
720                        labelLoader.clear( key );
721                        columnPool.remove( key );
722                }
723        }
724
725        /**
726         * GUI情報をクリアします。
727         * ここでは、関連するラベル、コードリソースの部分クリアも行います。
728         * GUI情報は、シーケンスに管理しているため、この処理1回ごとに、
729         * GUIData を全件再読み込みを行いますので、ご注意ください。
730         *
731         */
732        public void guiClear() {
733                final GUIData[] gui = guiLoader.getAllData();
734
735                for( int i=0; i<gui.length; i++ ) {
736                        final String key = gui[i].getGuiKey();
737                        labelLoader.clear( key );
738                }
739                codeLoader.clear( "CLASSIFY" );
740                guiLoader.clear();
741        }
742
743        /**
744         * リソースマネージャーをクリア(初期化)します。
745         *
746         * @og.rev 5.4.3.4 (2012/01/12) labelPool の削除追加
747         *
748         */
749        public void clear() {
750                columnLoader.clear();
751                codeLoader.clear();
752                labelLoader.clear();
753                guiLoader.clear();
754                columnPool.clear();
755        }
756}