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.List;
019import java.util.ArrayList;
020import java.util.Deque;                                                                                 // 6.8.4.2 (2017/12/25)
021import java.util.concurrent.ConcurrentLinkedDeque;                              // 6.8.4.2 (2017/12/25)
022import java.util.stream.Collectors;                                                             // 6.4.3.4 (2016/03/11)
023
024import org.opengion.hayabusa.common.HybsSystemException;
025import org.opengion.fukurou.util.StringUtil;
026import org.opengion.fukurou.util.HybsEntry;
027import org.opengion.fukurou.system.LogWriter;                                                   // 8.4.0.0 (2023/01/30)
028import static org.opengion.fukurou.system.HybsConst.CR ;                                // 6.1.0.0 (2014/12/26)
029import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;              // 6.1.0.0 (2014/12/26) refactoring
030
031/**
032 * 画面情報の取得の為のインターフェースです。
033 *
034 * {@GUI.XXXX} で、XXXX 部に、GUIInfo オブジェクトで定義されている
035 * 属性情報を取り出すことが出来ます。
036 *
037 * ・KEY           画面ID
038 * ・ADDRESS       実行アドレス
039 * ・REALADDRESS   実行実アドレス
040 * ・SEQUENCE      表示順
041 * ・GROUPS        メニュグループ
042 * ・CLASSIFY      メニュ分類
043 * ・LEVEL         メニュ階層番号
044 * ・LABEL         画面名称
045 * ・NAME          画面名称(=SNAME)
046 * ・SNAME         画面名称(short)
047 * ・LNAME         画面名称(long)
048 * ・ROLES         ロールズ
049 * ・MODE          アクセスモード列(mr,mw,-r,-w の羅列)
050 * ・TARGET        ターゲット
051 * ・PARAM         設定値(パラメータ)
052 * ・KBLINK        リンク区分
053 * ・DESCRIPTION   概要説明
054 * ・IMAGEKEY      イメージキー
055 * ・DYUPD         更新日時
056 * ・ISREAD        読取り許可[true/false]
057 * ・ISWRITE       書込み許可[true/false]
058 *
059 * @og.group リソース管理
060 *
061 * @version  4.0
062 * @author   Kazuhiko Hasegawa
063 * @since    JDK5.0,
064 */
065public final class GUIInfo implements Comparable<GUIInfo> {             // 4.3.3.6 (2008/11/15) Generics警告対応
066
067        private static final String YOYAKU = "|KEY|ADDRESS|REALADDRESS|SEQUENCE"
068                                                                                + "|GROUPS|CLASSIFY|LEVEL|LABEL|NAME"
069                                                                                + "|SNAME|LNAME|ROLES|MODE|TARGET"
070                                                                                + "|PARAM|KBLINK|DESCRIPTION|DYUPD|IMAGEKEY|" ;         // 5.5.2.5 (2012/05/21) イメージアイコン
071
072        private final GUIData   guiData         ;
073        private final LabelData labelData       ;
074        private final String[]  groupKeys       ;
075
076        /** メニューへの表示可否属性 */
077        private final boolean   menuFlag        ;
078        /** 書き込み許可属性 */
079        private final boolean   writeFlag       ;
080        /** ビットモード(UserInfo 加味済み) */
081        private final byte              bitMode         ;
082        /** 4.3.3.0 (2008/10/01) 強制プルダウン化属性 */
083        private final boolean   pulldownFlag;
084
085        /** この画面へのアクセス統計を管理します。 */
086        private final GUIAccessCount accessCount ;
087
088        private int   level     ;
089
090        /** 6.8.4.2 (2017/12/25) nextGui を、後入れ先出しに変更します。 */
091        private final Deque<String> nextGui = new ConcurrentLinkedDeque<>();    // 6.8.4.2 (2017/12/25) nextGui を、後入れ先出しに変更します。
092
093        /**
094         * コンストラクター
095         *
096         * 引数の bitMode は、UserInfo と加味済み。
097         *
098         * @og.rev 4.3.0.0 (2008/07/04) ファイル入出力制御追加
099         * @og.rev 4.3.3.0 (2008/10/01) 強制プルダウンモード追加
100         * @og.rev 8.4.0.0 (2023/01/31) RoleMode でthrow しても、インスタンスは生成する
101         *
102         * @param       guiData         画面データオブジェクトID
103         * @param       labelData       ラベルデータオブジェクト
104         * @param       bitMode ビットモード配列 "--:000","-r:001","-w:010","mr:101","mw:110" に対応した数字(0,1,2,5,6)
105         */
106        public GUIInfo( final GUIData guiData , final LabelData labelData , final byte bitMode ) {
107                this.guiData = guiData;
108                // 8.4.0.0 (2023/01/31) RoleMode でthrow しても、インスタンスは生成する。…ここでは、エラーをラベルに反映させる。
109                final String modeErrMsg = guiData.getModeErrMsg();
110                if( modeErrMsg == null ) {                      // エラーなし。
111                        this.labelData = labelData;
112                }
113                else {
114                        final String key = labelData.getKey();
115                        final String lbl = labelData.getLabel();
116                        final String tag = " : <span class=\"error\">" + modeErrMsg + "</span>";
117
118                        final String errMsg =  key + ":" + lbl + ":" + modeErrMsg ;
119                        LogWriter.log( errMsg );
120                        System.err.println( errMsg );
121
122                        this.labelData = new LabelData( key,lbl+tag );
123                }
124
125                groupKeys       = StringUtil.csv2Array( guiData.getGroups() );
126
127                menuFlag        = RoleMode.isMenu( bitMode );
128                writeFlag       = RoleMode.isWrite( bitMode );
129                pulldownFlag = RoleMode.isPulldown( bitMode ); // 4.3.3.0 (2008/10/01)
130                accessCount = new GUIAccessCount( guiData.getGuiKey() ) ;
131                this.bitMode = bitMode ;
132
133                level = guiData.getGuiLevel();
134        }
135
136        /**
137         * 画面情報 画面ID を取得します。
138         *
139         * @return      画面ID
140         */
141        public String getKey() {
142                return guiData.getGuiKey();
143        }
144
145        /**
146         * 実行アドレス情報を取得します。
147         *
148         * @return      実行アドレス
149         */
150        public String getAddress() {
151                return guiData.getAddress();
152        }
153
154        /**
155         * トップからの実行アドレス情報を取得します。
156         * コンテキスト名とリンク区分属性を利用して、サーバートップからのアドレスを
157         * 返します。ただし、GUIリソースに、http://~ または、.~ から始まるアドレスは
158         * そのまま、なにも変換せずに返します。
159         * 実アドレスには、param属性の情報を付加します。param属性は、接続文字を用いずに
160         * そのまま連結されますので、/index.jsp?AAA=XX&amp;BBB=YY という感じで "/" から
161         * はじめます。
162         *
163         * http://AAAA  ⇒  http://AAAA
164         * ../../AAAA/  ⇒  ../../AAAA/
165         * AAAA         ⇒  /CONTEXT_NAME/KBLINK/AAAA/    param なし
166         * AAAA         ⇒  /CONTEXT_NAME/KBLINK/AAAA/index.jsp?AAA=XX&amp;BBB=YY  param あり
167         *
168         * @og.rev 3.5.5.0 (2004/03/12) 新規追加
169         * @og.rev 4.0.0.0 (2005/01/31) param属性追加
170         *
171         * @return      実行実アドレス
172         */
173        public String getRealAddress() {
174                return guiData.getRealAddress();
175        }
176
177        /**
178         * トップからの実行アドレス情報を取得します。
179         * コンテキスト名とリンク区分属性を利用して、サーバートップからのアドレスを
180         * 返します。ただし、GUIリソースに、http://~ または、.~ から始まるアドレスは
181         * そのまま、なにも変換せずに返します。
182         * 実アドレスには、param属性の情報を付加します。param属性は、接続文字を用いずに
183         * そのまま連結されますので、/index.jsp?AAA=XX&amp;BBB=YY という感じで "/" から
184         * はじめます。
185         * また、アドレスの最後がスラッシュ(/)で終了している場合は、page属性を追加します。
186         *
187         * http://AAAA  ⇒  http://AAAA
188         * ../../AAAA/  ⇒  ../../AAAA/
189         * AAAA         ⇒  /CONTEXT_NAME/KBLINK/AAAA/    param なし
190         * AAAA         ⇒  /CONTEXT_NAME/KBLINK/AAAA/index.jsp?AAA=XX&amp;BBB=YY  param あり
191         *
192         * @og.rev 4.0.0.0 (2005/01/31) 新規追加(param属性追加)
193         *
194         * @param    page          実行ページ(index.jsp など)
195         *
196         * @return      実行実アドレス
197         */
198        public String getRealAddress( final String page ) {
199                return guiData.getRealAddress( page );
200        }
201
202        /**
203         * 画面の表示順を取得します。
204         *
205         * @return      画面の表示順
206         */
207        public int getSequence() {
208                return guiData.getSeqno();
209        }
210
211        /**
212         * 画面の階層番号(レベル)を取得します。
213         * 画面階層は、
214         *  0:予約階層(将来的にタブブラウザ対応時に使用
215         *  1:トップ階層(通常のメニューの分類として表示されます。)
216         *  2:選択階層(通常の折りたたみメニューの画面選択時に使用されます。)
217         *  3以下:下位階層(通常の選択メニューとして、1段下げて表示されます。)
218         * です。
219         * なお、これらの意味は、実際にメニューを作成/表示するクラスに依存します。
220         *
221         * @return      画面の表示順
222         */
223        public int getLevel() {
224                return level;
225        }
226
227        /**
228         * 画面の階層番号(レベル)をアップします。
229         *
230         * これは、レベルが3の場合(階層時の隠しメニュー)をレベル2に
231         * することで、常に見えているメニューに格上げします。
232         * 具体的には、設定値が隠しメニューの場合に、アクセスするとレベル2へ格上げ
233         * することで、個人単位で、過去の履歴に応じたメニュー配置が可能になります。
234         */
235        public void setLevelUp() {
236                if( level == 4 ) { level = 3; } // 4.0.0.0 (2007/10/30)
237        }
238
239        /**
240         * 画面情報 メニュグループのオリジナルキー を取得します。
241         * メニュグループは、CSV形式で複数登録できます。
242         *
243         * @return      メニュ分類のキー
244         */
245        public String getGroups() {
246                return guiData.getGroups();
247        }
248
249        /**
250         * 指定の文字列がグループに含まれているかどうかを判定します。
251         * メニュグループは、CSV形式で複数登録できますので、そのうちの
252         * どれかに含まれていれば、true を返します。
253         * このメニューそのものに、グループが指定されていない場合は、
254         * デフォルトグループという扱いで、true を返します。
255         * 引数が、null または、ゼロ文字列の場合も、同様に、true を返します。
256         *
257         * @param       group   判定するグループ
258         *
259         * @return      グループに含まれているかどうか
260         */
261        public boolean isGroupIn( final String group ) {
262                if( groupKeys.length == 0 || group == null || group.isEmpty() ) {
263                        return true;
264                }
265
266                // 8.5.4.2 (2024/01/12) PMD 7.0.0 ForLoopCanBeForeach
267//              for( int i=0; i<groupKeys.length; i++ ) {
268//                      if( group.equals( groupKeys[i] ) ) {
269                // 8.5.5.1 (2024/02/29) PMD 7.0.0 OnlyOneReturn メソッドには終了ポイントが 1 つだけ必要
270                boolean flag = false;
271                for( final String grpKey : groupKeys ) {
272                        if( group.equals( grpKey ) ) {
273//                              return true;
274                                flag = true;
275                                break;
276                        }
277                }
278//              return false;
279                return flag;
280        }
281
282        /**
283         * 画面情報 メニュ分類のオリジナルキー を取得します。
284         *
285         * @return      メニュ分類のキー
286         */
287        public String getClassify() {
288                return guiData.getClassify();
289        }
290
291        /**
292         * 画面情報 画面名称 を取得します。
293         * これは、加工前のラベルリソースに登録されている値です。
294         *
295         * @return      画面名称
296         */
297        public String getLabel() {
298                return labelData.getLabel();
299        }
300
301        /**
302         * 画面情報 画面名称を、指定のフラグに応じて取得します。
303         * true の場合、#getLongName() を、falseの場合、#getName() を
304         * 返します。
305         * この名称は、チップ表示付きの文字列を返します。
306         *
307         * @og.rev 8.2.1.0 (2022/07/15) 新規追加
308         *
309         * @param       flag true:名前(長) / false:名前(短)
310         * @return      画面名称(short)
311         */
312        public String getName( final boolean flag ) {
313                return flag ? getLongName() : getName();
314        }
315
316        /**
317         * 画面情報 画面名称(short) を取得します。
318         * この名称は、チップ表示付きの文字列を返します。
319         *
320         * @return      画面名称(short)
321         */
322        public String getName() {
323                return labelData.getShortLabel();
324        }
325
326        /**
327         * 画面情報 画面名称(long) を取得します。
328         * この名称は、チップ表示付きの文字列を返します。
329         *
330         * @return      画面名称(long)
331         */
332        public String getLongName() {
333                return labelData.getLongLabel();
334        }
335
336        /**
337         * 画面情報 ロール を取得します。
338         * ロールは、AAA|BBB|CCC と『|』の区切り文字で複数登録できます。
339         * ユーザーのロール(こちらも、XXX|YYY|AAAと複数登録可能)とマッチする
340         * ロールがあれば、その画面のアクセス許可があります。
341         * 読み書きと、メニュー表示は、アクセスモードで指定します。
342         *
343         * @return      ロール
344         */
345        public String getRoles() {
346                return guiData.getRoles();
347        }
348
349        /**
350         * アクセスモードを取得します。
351         *
352         * r,w,_ を各ロール毎に設定します。
353         * mr:メニューよりアクセスできる読取専用画面です。登録ボタンは表示されません。
354         * mw:メニューよりアクセスできる登録編集画面です。表示もします。
355         * -r:メニューに現れませんが、アクセスすることは可能です。読取専用。
356         * -w:メニューに現れませんが、アクセスすることは可能です。読み書き出来ます。
357         *
358         * この2文字ずつのセットが、各ロールに対応付けられたアクセス制御になります。
359         * ロールが、AAA|BBB|CCC|DDD で、モードが mw|mr|-r|-w であれば、
360         * AAA は、mw , BBB は、mr ,CCC は、-r ,DDD は -w と設定されたことになります。
361         * 特別に、2文字のみ登録された場合は、全ロールが同一モードに設定
362         * されたとみなします。
363         *
364         * @return      ロール毎のアクセスモード列(mr,mw,-r,-w の羅列)
365         */
366        public String getMode() {
367                return guiData.getMode();
368        }
369
370        /**
371         * 画面を表示する時のターゲット属性を取得します。
372         *
373         * @return      ターゲット
374         */
375        public String getTarget() {
376                return guiData.getTarget();
377        }
378
379        /**
380         * 画面を表示する時のパラメータ属性を取得します。
381         *
382         * @return      パラメータ
383         */
384        public String getParam() {
385                return guiData.getParam();
386        }
387
388        /**
389         * リンク区分属性を取得します。
390         *
391         * @og.rev 3.4.0.0 (2003/09/01) リンク区分(KBLINK)属性を追加。
392         *
393         * @return      リンク区分
394         */
395        public String getKblink() {
396                return guiData.getKblink();
397        }
398
399        /**
400         * 概要説明属性を取得します。
401         * 概要説明が設定されていない場合は、longName を返します。
402         *
403         * @og.rev 3.5.6.5 (2004/08/09) 概要説明(DESCRIPTION)属性を追加。
404         *
405         * @return      概要説明
406         */
407        public String getDescription() {
408                return labelData.getDescription() ;
409        }
410
411        /**
412         * 更新日時を取得します。
413         *
414         * @og.rev 5.3.3.0 (2011/03/01) 新規作成
415         *
416         * @return      更新日時
417         */
418        public String getDyupd() {
419                return guiData.getDyupd();
420        }
421
422        /**
423         * イメージアイコンのキーを返します。
424         *
425         * 画面にアイコンを追加する場合、jsp/menuImage フォルダに、画面ID と同じ名称の
426         * 画像ファイルを置く必要があります。
427         *
428         * ※ 6.3.8.4 (2015/10/09)
429         *    従来は、PARAM 属性に、IMAGE_KEY=XXXX と指定していましたが、
430         *    KBLINK(リンク区分) を使用するように変更しました。
431         *
432         * @og.rev 5.5.2.5 (2012/05/21) 新規追加
433         * @og.rev 6.3.8.4 (2015/10/09) KBLINK(リンク区分)を画面のイメージファイルに割り当てます。
434         *
435         * @return      イメージアイコンのキー
436         */
437        public String getImageKey() {
438                return guiData.getImageKey();
439        }
440
441        /**
442         * ロールモード情報を取得します。
443         *
444         * @og.rev 4.3.0.0 (2008/07/04) 新規追加
445         *
446         * @return      ロールモード
447         */
448        public RoleMode getRoleMode() {
449                return guiData.getRoleMode() ;
450        }
451
452        /**
453         * リードアクセス(読取り許可)の 可否を チェックします。
454         * アクセスチェックは、画面のロールをユーザーの
455         * それと比較して条件が含まれているかどうかを確認します。
456         * 条件が null (または0ストリング)の場合は、true となります。
457         * 条件の判断は、AND 条件です。
458         * さらに、その他の条件部分を判断して、OR 条件で先の結果と突き合わせます。
459         * ユーザーのロールが "root" の場合は、rw 属性のみのチェックで判断します。
460         *
461         * @og.rev 3.5.4.0 (2003/11/25) 引数にロールズを渡します。
462         *
463         * @return  アクセスOK:true  アクセス拒否:false
464         */
465        public boolean isRead() {
466                return menuFlag;
467        }
468
469        /**
470         * ライトアクセス(書込み許可)の 可否を チェックします。
471         * アクセスチェックは、画面のロールをユーザーの
472         * それと比較して条件が含まれているかどうかを確認します。
473         * 条件が null (または0ストリング)の場合は、true となります。
474         * 条件の判断は、AND 条件です。
475         * さらに、その他の条件部分を判断して、OR 条件で先の結果と突き合わせます。
476         * ユーザーのロールが "root" の場合は、rw 属性のみのチェックで判断します。
477         *
478         * @og.rev 3.5.4.0 (2003/11/25) 引数にロールズを渡します。
479         *
480         * @return  アクセスOK:true  アクセス拒否:false
481         */
482        public boolean isWrite() {
483                return writeFlag;
484        }
485
486        /**
487         * ボタンメニューにプルダウンを指定するのかをチェックします。
488         *
489         * @og.rev 4.3.3.0 (2008/10/01) 新規作成
490         *
491         * @return プルダウン化の場合true
492         */
493        public boolean isPulldown() {
494                return pulldownFlag;
495        }
496
497        /**
498         * 指定のユーザーロールに対するビット条件を取得します。
499         * この bitMode は、すでにユーザー単位に作成された値です。
500         *
501         * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
502         *
503         * @return アクセスビット
504         */
505        public byte getBitMode() {
506                return bitMode;
507        }
508
509        /**
510         * GUIInfoの属性文字列を取得します。
511         *
512         * ・KEY           画面ID
513         * ・ADDRESS       実行アドレス
514         * ・REALADDRESS   実行実アドレス
515         * ・SEQUENCE      表示順
516         * ・GROUPS        メニュグループ
517         * ・CLASSIFY      メニュ分類
518         * ・LEVEL         メニュ階層番号
519         * ・LABEL         画面名称
520         * ・NAME          画面名称(=SNAME)
521         * ・SNAME         画面名称(short)
522         * ・LNAME         画面名称(long)
523         * ・ROLES         ロール
524         * ・MODE          アクセスモード列(mr,mw,-r,-w の羅列)
525         * ・TARGET        ターゲット
526         * ・PARAM         設定値(パラメータ)
527         * ・KBLINK        リンク区分
528         * ・DESCRIPTION   概要説明
529         * ・IMAGEKEY      イメージキー
530         * ・DYUPD         更新日時
531         * ・ISREAD        読取り許可[true/false]
532         * ・ISWRITE       書込み許可[true/false]
533         *
534         * @og.rev 3.4.0.0 (2003/09/01) リンク区分(KBLINK)属性を追加。
535         * @og.rev 3.5.5.0 (2004/03/12) 実行実アドレス(REALADDRESS)属性を追加。
536         * @og.rev 3.5.6.5 (2004/08/09) 概要説明(DESCRIPTION)属性を追加。
537         * @og.rev 4.0.0.0 (2005/11/30) ISREAD,ISWRITE 属性を追加。
538         * @og.rev 5.3.3.0 (2011/03/01) 更新日時を追加
539         * @og.rev 5.5.2.5 (2012/05/21) IMAGEKEY 追加
540         * @og.rev 5.6.4.3 (2013/05/25) FAQ追加
541         * @og.rev 6.3.8.4 (2015/10/09) GE80(FAQテーブル)の取得は廃止。(helpタグで行う)
542         * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase.
543         *
544         * @param       key     キー
545         *
546         * @return      属性文字列の値
547         */
548        public String getAttribute( final String key ) {
549                final String rtn ;
550
551                if( key == null ) { rtn = null; }
552                else {
553                        if(      "KEY"         .equalsIgnoreCase( key ) ) { rtn = getKey(); }
554                        else if( "GUICLM"      .equalsIgnoreCase( key ) ) { rtn = labelData.getKey(); }
555                        else if( "ADDRESS"     .equalsIgnoreCase( key ) ) { rtn = getAddress(); }
556                        else if( "REALADDRESS" .equalsIgnoreCase( key ) ) { rtn = getRealAddress(); }
557                        else if( "SEQUENCE"    .equalsIgnoreCase( key ) ) { rtn = String.valueOf( getSequence() ); }
558                        else if( "GROUPS"      .equalsIgnoreCase( key ) ) { rtn = getGroups(); }
559                        else if( "CLASSIFY"    .equalsIgnoreCase( key ) ) { rtn = getClassify(); }
560                        else if( "LEVEL"       .equalsIgnoreCase( key ) ) { rtn = String.valueOf( getLevel() ); }
561                        else if( "LABEL"       .equalsIgnoreCase( key ) ) { rtn = getLabel(); }
562                        else if( "NAME"        .equalsIgnoreCase( key ) ) { rtn = getName(); }
563                        else if( "SNAME"       .equalsIgnoreCase( key ) ) { rtn = getName(); }
564                        else if( "LNAME"       .equalsIgnoreCase( key ) ) { rtn = getLongName(); }
565                        else if( "ROLE"        .equalsIgnoreCase( key ) ) { rtn = getRoles(); }
566                        else if( "ROLES"       .equalsIgnoreCase( key ) ) { rtn = getRoles(); }
567                        else if( "MODE"        .equalsIgnoreCase( key ) ) { rtn = getMode(); }
568                        else if( "TARGET"      .equalsIgnoreCase( key ) ) { rtn = getTarget(); }
569                        else if( "PARAM"       .equalsIgnoreCase( key ) ) { rtn = getParam(); }
570                        else if( "KBLINK"      .equalsIgnoreCase( key ) ) { rtn = getKblink(); }
571                        else if( "DESCRIPTION" .equalsIgnoreCase( key ) ) { rtn = getDescription(); }                           // 3.5.6.5 (2004/08/09)
572                        else if( "IMAGEKEY"    .equalsIgnoreCase( key ) ) { rtn = getImageKey(); }                                      // 3.5.6.5 (2004/08/09)
573                        else if( "DYUPD"       .equalsIgnoreCase( key ) ) { rtn = getDyupd(); }                                         // 5.5.2.5 (2012/05/21)
574                        else if( "ISREAD"      .equalsIgnoreCase( key ) ) { rtn = String.valueOf( isRead() ); }         // 4.0.0 (2005/11/30)
575                        else if( "ISWRITE"     .equalsIgnoreCase( key ) ) { rtn = String.valueOf( isWrite() ); }        // 4.0.0 (2005/11/30)
576        //              // 6.3.8.4 (2015/10/09) GE80(FAQテーブル)の取得は廃止。(helpタグで行う)
577        //              else if( "FAQ"         .equalsIgnoreCase( key ) ) { rtn = String.valueOf(isFaq()); }            // 5.6.4.3 (2013/05/24)
578                        else {
579                                final String errMsg = "属性文字列キーが不正です。 key=[" + key + "]"
580                                                        + CR
581                                                        + "予約語(" + YOYAKU + ") 以外は指定できません。" ;
582                                throw new HybsSystemException( errMsg );
583                        }
584                }
585                return rtn ;
586        }
587
588        /**
589         * GUIInfoの属性文字列の内部情報を返します。
590         * この内部情報の中には、getAttribute( String ) で取得できる管理情報です。
591         *
592         * @og.rev 4.0.0.0 (2004/12/31) 新規作成
593         * @og.rev 5.3.3.0 (2011/03/01) 更新日時を追加
594         * @og.rev 5.5.2.5 (2012/05/21) IMAGEKEY 追加
595         *
596         * @return      属性文字列のHybsEntryオブジェクト配列
597         * @og.rtnNotNull
598         */
599        public HybsEntry[] getEntrys() {
600                final List<HybsEntry> list = new ArrayList<>();
601
602                list.add( new HybsEntry( "GUI.KEY"         , getAttribute( "KEY"         ) , "画面ID" ) );
603                list.add( new HybsEntry( "GUI.GUICLM"      , getAttribute( "GUICLM"      ) , "画面カラムID" ) );
604                list.add( new HybsEntry( "GUI.ADDRESS"     , getAttribute( "ADDRESS"     ) , "実行アドレス" ) );
605                list.add( new HybsEntry( "GUI.REALADDRESS" , getAttribute( "REALADDRESS" ) , "実行実アドレス" ) );
606                list.add( new HybsEntry( "GUI.SEQUENCE"    , getAttribute( "SEQUENCE"    ) , "表示順" ) );
607                list.add( new HybsEntry( "GUI.GROUPS"      , getAttribute( "GROUPS"      ) , "メニュグループ" ) );
608                list.add( new HybsEntry( "GUI.CLASSIFY"    , getAttribute( "CLASSIFY"    ) , "メニュ分類" ) );
609                list.add( new HybsEntry( "GUI.LEVEL"       , getAttribute( "LEVEL"       ) , "メニュ階層番号" ) );
610                list.add( new HybsEntry( "GUI.LABEL"       , getAttribute( "LABEL"       ) , "画面名称" ) );
611                list.add( new HybsEntry( "GUI.NAME"        , getAttribute( "NAME"        ) , "画面名称(=SNAME)" ) );
612                list.add( new HybsEntry( "GUI.SNAME"       , getAttribute( "SNAME"       ) , "画面名称(short)" ) );
613                list.add( new HybsEntry( "GUI.LNAME"       , getAttribute( "LNAME"       ) , "画面名称(long)" ) );
614                list.add( new HybsEntry( "GUI.ROLES"       , getAttribute( "ROLES"       ) , "ロール" ) );
615                list.add( new HybsEntry( "GUI.MODE"        , getAttribute( "MODE"        ) , "アクセスモード列(mr,mw,-r,-w の羅列)" ) );
616                list.add( new HybsEntry( "GUI.TARGET"      , getAttribute( "TARGET"      ) , "ターゲット" ) );
617                list.add( new HybsEntry( "GUI.PARAM"       , getAttribute( "PARAM"       ) , "パラメータ" ) );
618                list.add( new HybsEntry( "GUI.KBLINK"      , getAttribute( "KBLINK"      ) , "リンク区分" ) );
619                list.add( new HybsEntry( "GUI.DESCRIPTION" , getAttribute( "DESCRIPTION" ) , "概要説明" ) );
620                list.add( new HybsEntry( "GUI.IMAGEKEY"    , getAttribute( "IMAGEKEY"    ) , "イメージキー" ) );      // 5.5.2.5 (2012/05/21)
621                list.add( new HybsEntry( "GUI.DYUPD"       , getAttribute( "DYUPD"       ) , "更新日時" ) );                // 5.3.3.0 (2011/03/01)
622                list.add( new HybsEntry( "GUI.ISREAD"      , getAttribute( "ISREAD"      ) , "読取り許可[true/false]" ) );
623                list.add( new HybsEntry( "GUI.ISWRITE"     , getAttribute( "ISWRITE"     ) , "書込み許可[true/false]" ) );
624
625//              return list.toArray( new HybsEntry[list.size()] );
626                return list.toArray( new HybsEntry[0] );        // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
627        }
628
629        /**
630         * データベース検索した数と、掛かった時間(ms)を、セットします。
631         * これは、セキュリティ上の監視フラグで、不必要に、大量の
632         * データが検索された場合や、不正なデータアクセスがあるかどうかを
633         * 監視するための統計情報を取得します。
634         * 画面オブジェクトは、各ユーザー毎に作成されているため、個々の
635         * ユーザー毎/画面毎のアクセス状況を見ることが可能になります。
636         *
637         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
638         *
639         * @param  cnt データベース検索した数
640         * @param  time データベース検索した数
641         * @param  query そのときのSQL文
642         */
643        public void addReadCount( final int cnt,final long time,final String query ) {
644                accessCount.addReadCount( cnt,time,query );
645        }
646
647        /**
648         * データベース登録した数と、掛かった時間(ms)を、セットします。
649         * これは、セキュリティ上の監視フラグで、不必要に、大量の
650         * データが登録された場合や、不正なデータアクセスがあるかどうかを
651         * 監視するための統計情報を取得します。
652         * 画面オブジェクトは、各ユーザー毎に作成されているため、個々の
653         * ユーザー毎/画面毎のアクセス状況を見ることが可能になります。
654         *
655         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
656         *
657         * @param  cnt データベース登録した数
658         * @param  time データベース検索した数
659         * @param  query そのときのSQL文
660         */
661        public void addWriteCount( final int cnt,final long time,final String query ) {
662                accessCount.addWriteCount( cnt,time,query );
663        }
664
665        /**
666         * この画面へのアクセス回数を、+1します。
667         * アクセス回数は、このメソッドの呼び出し回数のことです。
668         * 現状では、result.jsp 画面でセットすることで、アクセス数を
669         * 数えることにします。
670         *
671         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
672         *
673         */
674        public void addAccessCount() {
675                if( level == 4 ) { level = 3; } // 4.0.0.0 (2007/10/30)
676                accessCount.addAccessCount();
677        }
678
679        /**
680         * エラー発生時の件数を+1します。
681         * これは、エラー発生時に呼び出すことで、エラー件数をチェックすることが
682         * 可能になります。
683         * 一般にエラーには、予期するエラー(必須入力登録漏れ等)と、予期しないエラー
684         * がありますが、ここでは、Java の Exceptionが発生する予期しないエラーの
685         * 件数をカウントします。
686         *
687         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
688         *
689         */
690        public void addErrorCount() {
691                accessCount.addErrorCount();
692        }
693
694        /**
695         * この画面のアクセス統計オブジェクトを取得します。
696         *
697         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
698         *
699         * @return      アクセス統計オブジェクト
700         */
701        public GUIAccessCount getGUIAccessCount() {
702                return accessCount;
703        }
704
705        /**
706         * この画面の次にアクセスされた画面IDをセットします。
707         *
708         * これは、画面アクセスの履歴(順番)を管理する機能を提供します。
709         * 自分自身の次にアクセスされる画面IDの集合を管理することで
710         * QUERY画面上部のショートカットリンクに、次に使用する画面の
711         * リンクを用意することが可能になります。
712         *
713         * @og.rev 5.2.3.0 (2010/12/01) アクセス履歴管理
714         * @og.rev 6.8.4.2 (2017/12/25) nextGui を、後入れ先出しに変更します。
715         *
716         * @param       guiKey  この画面の次にアクセスされた画面ID
717         */
718        public void setNextGuiKey( final String guiKey ) {
719                // 自分自身の場合は、セットしない。
720                if( guiKey != null && !guiKey.equals( getKey() ) ) {
721                        nextGui.remove( guiKey );                       // 実装は、List なので、一旦削除(Setの代用のつもり)
722                        nextGui.addFirst( guiKey );                     // 要素の最初に挿入
723                }
724        }
725
726        /**
727         * この画面の次にアクセスされた画面IDのCSV文字列を取得します。
728         *
729         * これは、画面アクセスの履歴(順番)をCSV形式で取り出します。
730         * アクセス履歴を外部記憶媒体に出力する場合に使用します。
731         *
732         * @og.rev 5.2.3.0 (2010/12/01) アクセス履歴管理
733         * @og.rev 6.4.3.4 (2016/03/11) CSV形式の文字連結を、stream 経由で行います。
734         *
735         * @return      この画面の次にアクセスされた画面IDのCSV文字列
736         * @og.rtnNotNull
737         */
738        public String getNextGuiKeys() {
739                return nextGui.stream()
740                                        .collect( Collectors.joining( "," ) );
741        }
742
743        /**
744         * この画面の次にアクセスされた画面IDの文字列配列で取得します。
745         *
746         * これは、画面アクセスの履歴(順番)を文字列配列で取り出します。
747         *
748         * @og.rev 5.2.3.0 (2010/12/01) アクセス履歴管理
749         *
750         * @return      この画面の次にアクセスされた画面IDの文字列配列
751         */
752        public String[] getNextGuiArray() {
753                // 6.9.8.0 (2018/05/28) FindBugs:java.util.concurrent のインスタンスで同期化している
754//              return nextGui.toArray( new String[nextGui.size()] );
755                return nextGui.toArray( new String[0] );        // 8.5.4.2 (2024/01/12) PMD 7.0.0 OptimizableToArrayCall 対応
756
757//              final String[] rtnAry ;
758//              synchronized( nextGui ) {
759//                      rtnAry = nextGui.toArray( new String[nextGui.size()] );
760//              }
761//
762//              return rtnAry ;
763        }
764
765        /**
766         * 自然比較メソッド
767         * インタフェース Comparable の 実装に関連して、再定義しています。
768         * 登録されたシーケンス(画面の表示順)で比較します。
769         * equals メソッドでは、キーの同一性のみに着目して判定しています。
770         * この比較では、(運用上同一キーは発生しませんが)たとえ同一キーが存在した
771         * としても、その比較値が同じになることを保証していません。
772         *
773         * @param   other 比較対象のObject
774         *
775         * @return  このオブジェクトが指定されたオブジェクトより小さい場合は負の整数、等しい場合はゼロ、大きい場合は正の整数
776         * @throws  ClassCastException 引数が GUIInfo ではない場合
777         * @throws  IllegalArgumentException 引数が null の場合
778         */
779        @Override       // Comparable
780        public int compareTo( final GUIInfo other ) {           // 4.3.3.6 (2008/11/15) Generics警告対応
781                if( other == null ) {
782                        final String errMsg = "引数が、null です。" ;
783                        throw new IllegalArgumentException( errMsg );
784                }
785                return getSequence() - other.getSequence();             // 4.3.3.6 (2008/11/15) Generics警告対応
786        }
787
788        /**
789         * このオブジェクトと他のオブジェクトが等しいかどうかを示します。
790         * 画面は、画面IDが等しければ、言語や表示順に関係なく同一とみなされます。
791         * GUIInfo は、ユーザー個別に扱われ、そのグループには、key は唯一で、かつ
792         * 同一言語内で扱われるオブジェクトの為、同一とみなします。
793         *
794         * @param   object 比較対象の参照オブジェクト
795         *
796         * @return      引数に指定されたオブジェクトとこのオブジェクトが等しい場合は true、そうでない場合は false
797         */
798        @Override
799        public boolean equals( final Object object ) {
800                // 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
801                return object instanceof GUIInfo && getKey().equals( ((GUIInfo)object).getKey() );
802        }
803
804        /**
805         * オブジェクトのハッシュコード値を返します。
806         * このメソッドは、java.util.Hashtable によって提供されるような
807         * ハッシュテーブルで使用するために用意されています。
808         * equals( Object ) メソッドをオーバーライトした場合は、hashCode() メソッドも
809         * 必ず 記述する必要があります。
810         * この実装では、getKey().hashCode() と同値を返します。
811         *
812         * @return  このオブジェクトのハッシュコード値
813         */
814        @Override
815        public int hashCode() {
816                return getKey().hashCode() ;
817        }
818
819        /**
820         * オブジェクトの識別子として、詳細な画面情報を返します。
821         *
822         * @og.rev 3.4.0.0 (2003/09/01) リンク区分(KBLINK)属性を追加。
823         * @og.rev 3.5.5.0 (2004/03/12) 実行アドレス(ADDRESS)属性を追加。
824         * @og.rev 5.3.3.0 (2011/03/01) 更新日時を追加
825         * @og.rev 5.5.2.5 (2012/05/21) IMAGEKEY 追加
826         *
827         * @return  詳細な画面情報
828         * @og.rtnNotNull
829         */
830        @Override
831        public String toString() {
832                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE )
833                        .append( "key        :").append( getKey()           ).append( CR )      // 画面ID
834                        .append( "lvlclm     :").append( labelData.getKey() ).append( CR )      // 画面カラムID
835                        .append( "address    :").append( getAddress()       ).append( CR )      // 実行アドレス
836                        .append( "sequence   :").append( getSequence()      ).append( CR )      // 表示順
837                        .append( "groups     :").append( getGroups()        ).append( CR )      // メニュグループ
838                        .append( "classify   :").append( getClassify()      ).append( CR )      // メニュ分類
839                        .append( "level      :").append( getLevel()         ).append( CR )      // 階層レベル
840                        .append( "name       :").append( getName()          ).append( CR )      // 画面名称
841                        .append( "longName   :").append( getLongName()      ).append( CR )      // 画面名称(long)
842                        .append( "roles      :").append( getRoles()         ).append( CR )      // ロール
843                        .append( "mode       :").append( getMode()          ).append( CR )      // アクセスモード  "rwrwrw"
844                        .append( "target     :").append( getTarget()        ).append( CR )      // ターゲット
845                        .append( "kblink     :").append( getKblink()        ).append( CR )      // リンク区分
846                        .append( "description:").append( getDescription()   ).append( CR )      // 概要説明
847                        .append( "imageKey   :").append( getImageKey()      ).append( CR )      // イメージキー 5.5.2.5 (2012/05/21)
848                        .append( "dyupd      :").append( getDyupd()         ).append( CR );     // 更新日時
849                return rtn.toString();
850        }
851}