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