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