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