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.sql.SQLException;
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.opengion.fukurou.db.DBSimpleTable;
027import org.opengion.fukurou.db.DBUtil;
028import org.opengion.fukurou.util.ApplicationInfo;
029import org.opengion.fukurou.util.Cleanable;
030import org.opengion.fukurou.util.HybsEntry;
031import org.opengion.fukurou.util.LogWriter;
032import org.opengion.hayabusa.common.HybsSystem;
033import org.opengion.hayabusa.common.HybsSystemException;
034import org.opengion.hayabusa.common.UserSummary;
035import org.opengion.hayabusa.db.DBEditConfig;
036import org.opengion.hayabusa.db.DBEditConfigManager;
037
038/**
039 * ユーザー情報の取得の為のインターフェースを実装したクラスです。
040 *
041 * ログイン時のパスワードのチェックや,国名の識別ID,ポータルページのURLなど
042 * 個人情報を管理させます。
043 * 特に,画面アクセス時の権限やメールの送信,各画面にユーザー情報を表示したり,
044 * エラー時のログファイル,テンポラリディレクトリなども管理します。
045 *
046 * {@USER.XXXX} で、XXXX 部に、UserInfo オブジェクトで定義されている
047 * 属性情報を取り出すことが出来ます。
048 *
049 * 以下の値は UserInfo オブジェクトの項目から取得します。
050 * ・JNAME      ユーザー日本語名称
051 * ・ID         ユーザーID
052 * ・INFO       ユーザー情報(ユーザーID:日本語名称)
053 * ・LANG       言語
054 * ・ROLES      ロール
055 * ・IPADDRESS  IPアドレス
056 * ・LOGINTIME  ログイン時刻
057 * ・LASTACCESS 最終アクセス画面ID
058 *
059 * 以下の値はあらかじめ、動的に作成されます。
060 * ・YMD       8byte の今日のシステム日付
061 * ・YMDH    14byte の今日のシステム日時
062 *
063 * それ以外は,外部より設定された値です。
064 * 従来は、USER.IDNO はUSER.ID が5Byte以上の時のみ先頭1文字を除いたユーザーIDとして
065 * オブジェクト項目からの取得でしたが、現在は初期値として設定してあります。
066 * 外部より再設定可能になっています。
067 *
068 * @og.group リソース管理
069 *
070 * @version  4.0
071 * @author   Kazuhiko Hasegawa
072 * @since    JDK5.0,
073 */
074public class UserInfo implements UserSummary , Cleanable {
075        private static final long serialVersionUID = 568120130913L ;    // 5.6.8.1 (2013/09/13)
076
077        // ユーザーリソースのキー指定読み込みのクエリー 
078        private static final String QUERY_PARAM = HybsSystem.sys( "USER_PARAMETER_SQL" );
079
080        /** 5.6.8.1 (2013/09/13) 最終リクエスト情報のユーザー永続化情報(GE20)へのセーブに使用するキーの接頭語 */
081        private static final String LAST_REQUEST_DATA_SUFIX = "LAST_REQUEST_" ;
082
083        // アクセス統計テーブル(GE15)への接続先を、リソースの接続先より取得します。
084        private final String DBID = HybsSystem.sys( "RESOURCE_DBID" );
085
086        //private static final String YOYAKU = "|JNAME|ID|INFO|LANG|ROLES|IPADDRESS|LOGINTIME|LASTACCESS|YMD|YMDH|" ;
087        private static final String YOYAKU = "|JNAME|ID|INFO|LANG|ROLES|IPADDRESS|LOGINTIME|LASTACCESS|YMD|YMDH|LASTGAMENNM" ; // 4.4.0.1 (2009/08/08)
088
089        private final boolean useAccessTable = HybsSystem.sysBool( "USE_ACCESS_TOKEI_TABLE" );
090
091        private final String    userID  ;
092        private       String    lang    ;       // 5.1.4.0 (2010/03/01) lang を書き換え可能とする。
093        private final String    jname   ;
094        private final String    roles   ;
095        private final String    droles  ; // 4.4.0.0 (2009/08/02) データロール対応
096        private final String    ipAddress       ;
097        private final long              loginTime       ;
098        private final Map<String,String>        attribute  ;
099        private final RoleMode  roleMode ;              // ロールズとモードを管理するオブジェクト
100        private final DataRole  dataRole ;              // データロールを管理するオブジェクト
101
102        private final int               hashcode        ;                               // 3.5.6.0 (2004/06/18)
103        private Map<String,GUIInfo>     guiMap  ;                               // 4.0.0 (2005/01/31)
104        private           boolean       isInfoSet       = false;                        // 4.0.0 (2005/01/31)
105        private           long          usedTime        = 0L;                           // 4.0.0 (2005/01/31)
106        private final Map<String,String>        paramMap = new HashMap<String,String>();
107        private final Object    guiLock         = new Object();
108        private final String    systemId        ;
109        private Map<String,FavoriteGUIData> favoriteGuiMap = null;      // 4.1.1.0 (2008/01/22)
110        private Set<String> forbidAddrSet       = null;                 // 5.2.0.0 (2010/09/01)
111        private final DBEditConfigManager editMgr = new DBEditConfigManager(); // 5.3.6.0 (2011/06/01)
112
113        private final Map<String,String>        lastRequestMap = new HashMap<String,String>();  // 5.6.8.1 (2013/09/13)
114
115        /** コネクションにアプリケーション情報を追記するかどうか指定 */
116        public static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
117
118        // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
119        private final ApplicationInfo appInfo;
120
121        // ユーザー永続化情報(GE20)テーブル 読み込み用SQL
122        // 4.3.4.0 (2008/12/01) ROLE='*'も検索できるようにする
123        // 5.3.6.0 (2011/06/01) USERID='*'も検索できるようにする
124        private static final String QUERY_GE20  = "select PARAM_ID,PARAM from GE20"
125                                                                                        +       " where SYSTEM_ID = ? and USERID in ( ?, '*' )"
126                                                                                        +       " and ROLES in ( ?, '*' ) and FGJ = '1'"
127                                                                                        +       " order by USERID,ROLES";
128
129        // 4.3.4.0 (2008/12/01) ユーザー永続化情報(GE20)にセーブ時に存在チェックを行うためのSQL
130        // 4.3.4.4 (2009/01/01) private static を付加
131        private static final String QUERY_GE20_KEY      = "select KBSET from GE20"
132                                                                                        +       " where SYSTEM_ID = ? and USERID = ?"
133                                                                                        +       " and ROLES = ? and PARAM_ID = ? and FGJ = '1'";
134
135        // 5.2.3.0 (2010/12/01) アクセス履歴管理
136        private GUIInfo lastGuiInfo = null;
137
138        // saveGUIAccessInfo() メソッドでしか使用しない、定数宣言
139        private static final int C_SYSTEM_ID            = 0 ;
140        private static final int C_USERID                       = 1 ;
141        private static final int C_USERADRS                     = 2 ;
142        private static final int C_HOSTADRS                     = 3 ;
143        private static final int C_GUIKEY                       = 4 ;
144        private static final int C_DYLOGIN                      = 5 ;
145        private static final int C_DYLOGOUT                     = 6 ;
146        private static final int C_USED_TIME            = 7 ;
147        private static final int C_CNT_ACCESS           = 8 ;
148        private static final int C_CNT_ERROR            = 9 ;
149        private static final int C_CNT_READ                     = 10 ;
150        private static final int C_CNT_WRITE            = 11 ;
151        private static final int C_TM_TOTAL_QUERY       = 12 ;
152        private static final int C_TM_MAX_QUERY         = 13 ;
153        private static final int C_MAX_QUERY            = 14 ;
154        private static final int C_FGJ                          = 15 ;
155        private static final int C_DYSET                        = 16;
156        private static final int C_DYUPD                        = 17;
157        private static final int C_USRSET                       = 18;
158        private static final int C_USRUPD                       = 19;
159        private static final int C_PGUPD                        = 20;
160
161        // ユーザー永続化情報(GE20)設定でしか使用しない変数の宣言
162        private static final int C_GE20_SYSTEM_ID       = 0;
163        private static final int C_GE20_USERID          = 1;
164        private static final int C_GE20_ROLES           = 2;
165        private static final int C_GE20_PARAM_ID        = 3;
166        private static final int C_GE20_PARAM           = 4;
167        private static final int C_GE20_KBSET           = 5;
168        private static final int C_GE20_FGJ                     = 6;
169        private static final int C_GE20_DYSET           = 7;
170        private static final int C_GE20_DYUPD           = 8;
171        private static final int C_GE20_USRSET          = 9;
172        private static final int C_GE20_USRUPD          = 10;
173        private static final int C_GE20_PGUPD           = 11;
174
175        private static final int GE20_KBSET_READONLY    = 1;
176        private static final int GE20_KBSET_WRITABLE    = 2;
177
178        // ロールは全て*で登録する。アプリケーションから動的に登録される値を、
179        // ロール単位設定しても、ロール変更時に整合性が合わない可能性大なので、
180        // UserInfoで設定する場合は、全てのロールで有効とする。
181        private static final String GE20_ROLES = "*";
182
183        /**
184         * コンストラクター
185         *
186         * @og.rev 3.0.0.1 (2003/02/14) ユーザー毎のエンコード指定方法を廃止します。
187         * @og.rev 3.1.3.0 (2003/04/10) ユーザー情報から、エンコード情報を削除する。
188         * @og.rev 3.4.0.3 (2003/09/10) "root","manager","admin" のロールを、すべて root 権限を与える。
189         * @og.rev 3.8.5.3 (2006/06/30) USE_USER_IDNO_C_SAPLESS を判定条件に加える。
190         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
191         * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
192         * @og.rev 4.4.0.0 (2009/08/02) データロール対応
193         * @og.rev 5.3.6.0 (2011/06/01) ユーザー永続化情報(GE20)の読み込みをUserInfoFactoryから移動
194         *
195         * @param       userID          ユーザー
196         * @param       lang            言語
197         * @param       jname           日本語名称
198         * @param       roles           ロール
199         * @param       droles          データロール
200         * @param       systemId        システムID
201         * @param       ipAddress       IPアドレス
202         * @param   appInfo             アプリ情報オブジェクト
203         */
204        public UserInfo( final String userID            ,
205                                         final String lang                      ,
206                                         final String jname                     ,
207                                         final String roles                     ,
208                                         final String droles            , // 4.4.0.0 (2009/08/02)
209                                         final String systemId          ,
210                                         final String ipAddress         ,
211                                         final ApplicationInfo appInfo  ) {
212                this.userID             = userID        ;
213                this.lang               = lang          ;
214                this.jname              = jname         ;
215                this.roles              = roles         ;
216                this.droles             = droles        ; // 4.4.0.0 (2009/08/02)
217                this.systemId   = systemId      ;
218                this.roleMode   = RoleMode.newInstance( roles );        // 4.3.0.0 (2008/07/04) ロールモード
219                this.dataRole   = DataRole.newInstance( droles, systemId, appInfo ); // 4.4.0.0 (2009/08/02)
220                this.ipAddress  = ipAddress     ;
221                this.appInfo    = appInfo       ;
222                loginTime               = System.currentTimeMillis();
223                usedTime                = loginTime;
224                attribute               = new HashMap<String,String>();
225
226                // 3.5.6.0 (2004/06/18) hashCode を計算しておきます。
227                hashcode = (int)(loginTime^(loginTime>>>32)) ;
228
229                // 3.8.1.2 (2005/12/19) USER.IDNO をAttributeにセットする。
230                // 3.8.5.3 (2006/06/30) USE_USER_IDNO_C_SAPLESS を判定条件に加える。
231                boolean IDNO_C_SAPLESS = HybsSystem.sysBool( "USE_USER_IDNO_C_SAPLESS" );
232                String idno = ( userID.length() > 5 && IDNO_C_SAPLESS ) ? userID.substring(1) : userID ;
233                attribute.put( "IDNO",idno ) ;                          // コンストラクタ内なので、同期処理は入れていません。
234
235                // ユーザーパラメータなどの初期設定を行います。
236                initLoad() ;
237
238                // 5.3.6.0 (2011/06/01) ユーザー永続化情報(GE20)からDBに保存されたUserInfo情報を読み出します。
239                dbLoad();
240
241                // 5.3.6.0 (2011/06/01) Edit情報の一覧を作成します。
242                makeEditConfigMap();
243        }
244
245        /**
246         * ユーザーパラメータを取得します。
247         * ユーザーパラメーターは、通常、GE16 テーブルより取得します。
248         * 取得するSQL文は、SystemData の USER_PARAMETER_SQL に記述しておきます。
249         * ユーザーパラメータに、値が存在しない場合は、システムリソースより
250         * 取得します。
251         *
252         * @param       key     パラメータキー
253         *
254         * @return      パラメータ値(ユーザーパラメータになければ、システムリソースより取得
255         */
256        public String getParameter( final String key ) {
257                String val = null;
258                if( key != null ) {
259                        synchronized( paramMap ) {
260                                val = paramMap.get( key );
261                        }
262                        if( val == null ) { val = HybsSystem.sys( key ); }
263                }
264                return val;
265        }
266
267        /**
268         * ユーザーログイン時刻を取得します。
269         *
270         * @return      ログイン時刻
271         */
272        public long getLoginTime() {
273                return loginTime;
274        }
275
276        /**
277         * ユーザーのログインIPアドレスを取得します。
278         *
279         * @return      IPアドレス
280         *
281         */
282        public String getIPAddress() {
283                return ipAddress;
284        }
285
286        /**
287         * ユーザーを取得します。
288         *
289         * @return      ユーザー
290         *
291         */
292        public String getUserID() {
293                return userID;
294        }
295
296        /**
297         * ユーザー情報ロケール(言語)を取得します。
298         *
299         * @return      ロケール(言語)
300         */
301        public String getLang() {
302                return lang ;
303        }
304
305        /**
306         * ユーザー情報ロケール(言語)をセットします。
307         *
308         * @og.rev 5.1.4.0 (2010/03/01) lang を書き換え可能とする。
309         *
310         * @param newLang       ロケール(言語)
311         */
312        public void setLang( final String newLang ) {
313                lang = newLang ;
314        }
315
316        /**
317         * ユーザー情報 名称(日本語)を取得します。
318         *
319         * @return      名称(日本語)
320         */
321        public String getJname() {
322                return jname ;
323        }
324
325        /**
326         * ユーザー情報 ロール(役割)を取得します。
327         *
328         * @return      ロール(役割)
329         */
330        public String getRoles() {
331                return roles ;
332        }
333
334        /**
335         * ロールモード情報を取得します。
336         *
337         * @og.rev 4.3.0.0 (2008/07/04) 新規追加
338         *
339         * @return      ロールモード情報
340         */
341        public RoleMode getRoleMode() {
342                return roleMode ;
343        }
344
345        /**
346         * オブジェクトの識別子として,ユーザー情報を返します。
347         *
348         * @return  ユーザー情報
349         */
350        public String getInfo() {
351                StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
352                rtn.append( userID ).append( " : " );
353                rtn.append( jname  ).append( HybsSystem.CR );
354                return rtn.toString();
355        }
356
357        /**
358         * UserInfoの属性文字列を登録します。
359         *
360         * 予約文字(JNAME,ID,INFO,LANG,ROLES,IPADDRESS,LOGINTIME,LASTACCESS,YMD,YMDH,LASTGAMENNM)を
361         * 登録しようとした場合は、エラーにします。
362         *
363         * ※ 属性文字列キーが不正の場合、HybsSystemException が、throw されます。
364         *
365         * @param       key     キー
366         * @param       value   値
367         * @param       save    ユーザー永続化情報(GE20)に情報を保存するか
368         */
369        public void setAttribute( final String key,final String value, final boolean save ) {
370                setAttribute( key, value, save, false );
371        }
372
373        /**
374         * UserInfoの属性文字列を登録します。
375         *
376         * 予約文字(JNAME,ID,INFO,LANG,ROLES,IPADDRESS,LOGINTIME,LASTACCESS,YMD,YMDH,LASTGAMENNM)を
377         * 登録しようとした場合は、エラーにします。
378         *
379         * ※ 属性文字列キーが不正の場合、HybsSystemException が、throw されます。
380         *
381         * @og.rev 3.5.6.0 (2004/06/18) synchronized をattribute に行います。
382         * @og.rev 4.3.4.0 (2008/12/01) ユーザー永続化情報(GE20)へ登録するかのフラグを追加
383         * @og.rev 5.3.6.0 (2011/06/01) ユーザー永続化情報(GE20)へ登録時に全ユーザー公開するかのフラグを追加
384         * @og.rev 5.6.8.1 (2013/09/13) 値が null、またはゼロ文字列の場合、処理しません。
385         * @og.rev 5.7.2.2 (2014/01/24) 値が null、またはゼロ文字列の場合でも処理します。(5.6.8.1 以前に戻します)
386         *
387         * @param       key     キー
388         * @param       value   値
389         * @param       save    ユーザー永続化情報(GE20)に情報を保存するか
390         * @param       common  ユーザー永続化情報(GE20)に保存した情報を全ユーザー公開するか
391         */
392        private void setAttribute( final String key,final String value, final boolean save, final boolean common ) {
393                if( key != null && YOYAKU.indexOf( "|" + key + "|" ) < 0 ) {
394                        // 5.6.8.1 (2013/09/13) 値が null、またはゼロ文字列の場合、処理しません。
395                        // 5.7.2.2 (2014/01/24) 値が null、またはゼロ文字列の場合でも処理します。(5.6.8.1 以前に戻します)
396                        synchronized( attribute ) {
397                                attribute.put( key,value ) ;
398                        }
399
400                        // 4.3.4.0 (2008/12/01) 追加
401                        if( save ) {
402                                savePermanently( key ,value, common );
403                        }
404                }
405                else {
406                        String errMsg = "属性文字列キーが不正です。 key=[" + key + "]"
407                                                + HybsSystem.CR
408                                                + "null または予約語(" + YOYAKU + ") は指定できません。";
409                        throw new HybsSystemException( errMsg );
410                }
411        }
412
413        /**
414         * UserInfoの属性文字列を取得します。
415         *
416         * 以下の値は UserInfo オブジェクトの項目から取得します。
417         * <pre>
418         * ・JNAME      ユーザー日本語名称
419         * ・ID         ユーザーID
420         * ・IDNO       (初期値)USER.ID が5Byte以上の時のみ先頭1文字を除いたユーザーID
421         * ・INFO       ユーザー情報(ユーザーID:日本語名称)
422         * ・LANG       言語
423         * ・ROLES      ロール
424         * ・IPADDRESS  IPアドレス
425         * ・LOGINTIME  ログイン時刻
426         * ・LASTACCESS 最終アクセス画面ID
427         * ・LASTGAMENNM 最終アクセス画面名
428         *
429         * 以下の値はあらかじめ、動的に作成されます。
430         * ・YMD       8byte の今日のシステム日付
431         * ・YMDH    14byte の今日のシステム日時
432         * </pre>
433         *
434         * それ以外は,外部より設定された値です。
435         *
436         * @og.rev 2.1.0.2 (2002/11/07) USER.IDNO の返す値をUSER.ID が5Byte以上の時のみ、
437         * 先頭1文字を除いた値を返す様に変更。それ以外は、USER.IDを返す。
438         *
439         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応  ENCODE 追加
440         * @og.rev 3.1.3.0 (2003/04/10) ユーザー情報から、エンコード情報を削除する。
441         * @og.rev 3.5.4.2 (2003/12/15) ENAME,MAILTO、MAILUSERID、MAILPASSWD、GROUP、PROJECTを削除する。
442         * @og.rev 3.5.6.0 (2004/06/18) synchronized をattribute に行います。
443         * @og.rev 3.6.0.0 (2004/09/17) PASSWD を削除する。
444         * @og.rev 3.8.1.2 (2005/12/19) USER.IDNO を削除する。(外部設定可能にするため)
445         * @og.rev 3.8.7.0 (2006/12/15) ApplicationInfoオブジェクトから最終アクセス画面を取得
446         * @og.rev 4.4.0.0 (2009/08/02) データロール属性対応
447         * @og.rev 4.4.0.1 (2009/08/08) LASTGAMENNM追加
448         *
449         * @param       key     キー
450         *
451         * @return      UserInfoの属性文字列
452         */
453        public String getAttribute( final String key ) {
454                if( key == null ) { return null; }
455                String rtn = null;
456
457                if(      key.equalsIgnoreCase( "JNAME"  ) ) { rtn = jname; }
458                else if( key.equalsIgnoreCase( "ID"             ) ) { rtn = userID; }
459                else if( key.equalsIgnoreCase( "INFO"           ) ) { rtn = getInfo(); }
460                else if( key.equalsIgnoreCase( "LANG"           ) ) { rtn = lang; }
461                else if( key.equalsIgnoreCase( "ROLE"           ) ) { rtn = roles; }
462                else if( key.equalsIgnoreCase( "ROLES"          ) ) { rtn = roles; }
463                else if( key.equalsIgnoreCase( "DROLES"         ) ) { rtn = droles; } // 4.4.0.0 (2009/08/02)
464                else if( key.equalsIgnoreCase( "IPADDRESS"      ) ) { rtn = ipAddress; }
465                else if( key.equalsIgnoreCase( "LOGINTIME"      ) ) {
466                        rtn = HybsSystem.getDate( loginTime );
467                }
468                else if( key.equalsIgnoreCase( "YMD" ) ) {
469                        rtn = HybsSystem.getDate( "yyyyMMdd" );
470                }
471                else if( key.equalsIgnoreCase( "YMDH" ) ) {
472                        rtn = HybsSystem.getDate( "yyyyMMddHHmmss" );
473                }
474                else if( key.equalsIgnoreCase( "LASTACCESS"  ) ) {              // 3.8.7.0 (2006/12/15)
475                        if( appInfo != null ) { rtn = appInfo.getGamenId(); }
476                }
477                else if ( key.equalsIgnoreCase( "LASTGAMENNM" ) ){              // 4.4.0.1 (2009/08/08)
478                        if( appInfo != null && appInfo.getGamenId() != null){
479                                if( getGUIInfo( appInfo.getGamenId() ) != null){
480                                        rtn = getGUIInfo( appInfo.getGamenId() ).getName();
481                                }
482                        }
483                }
484                else {
485                        synchronized( attribute ) {
486                                rtn = attribute.get( key ) ;
487                        }
488                }
489                return rtn ;
490        }
491
492        /**
493         * UserInfoの属性文字列の内部情報を返します。
494         * この内部情報の中には、UserInfo 自身の管理情報も含めます。
495         * 独自管理キーは、JNAME,ID,IDNO,INFO,LANG,ROLES,IPADDRESS,LOGINTIME,LASTACCESS,LASTGAMENNM です。
496         *
497         * それ以外は,外部より設定された値です。
498         *
499         * @og.rev 4.0.0.0 (2004/12/31) 新規作成
500         * @og.rev 4.4.0.1 (2009/08/08) LASTGAMENNM追加
501         *
502         * @return 属性文字列のHybsEntryオブジェクト配列
503         */
504        public HybsEntry[] getEntrys() {
505                List<HybsEntry> list = new ArrayList<HybsEntry>();
506
507                list.add( new HybsEntry( "JNAME"                , getAttribute( "JNAME"         ) ,"ユーザー日本語名称" ) );
508                list.add( new HybsEntry( "ID"                   , getAttribute( "ID"            ) ,"ユーザーID" ) );
509                list.add( new HybsEntry( "IDNO"                 , getAttribute( "IDNO"          ) ,"USER.ID が5Byte以上の時のみ先頭1文字を除いたユーザーID" ) );
510                list.add( new HybsEntry( "INFO"                 , getAttribute( "INFO"          ) ,"ユーザー情報(ユーザーID:日本語名称)" ) );
511                list.add( new HybsEntry( "LANG"                 , getAttribute( "LANG"          ) ,"言語" ) );
512                list.add( new HybsEntry( "ROLES"                , getAttribute( "ROLES"         ) ,"ロールズ" ) );
513                list.add( new HybsEntry( "IPADDRESS"    , getAttribute( "IPADDRESS" ) ,"IPアドレス" ) );
514                list.add( new HybsEntry( "LOGINTIME"    , getAttribute( "LOGINTIME" ) ,"ログイン時刻" ) );
515                list.add( new HybsEntry( "LASTACCESS"   , getAttribute( "LASTACCESS" ) ,"最終アクセス画面ID" ) );
516                list.add( new HybsEntry( "LASTGAMENNM"  , getAttribute( "LASTGAMENNM") ,"最終アクセス画面名" ) ); // 4.4.0.1 (2009/08/08)
517                list.add( new HybsEntry( "YMD"                  , getAttribute( "YMD"           ) ," 8byte の今日のシステム日付" ) );
518                list.add( new HybsEntry( "YMDH"                 , getAttribute( "YMDH"          ) ,"14byte の今日のシステム日時" ) );
519
520                synchronized( attribute ) {
521                        String[] keys = attribute.keySet().toArray( new String[attribute.size()] );
522                        Arrays.sort( keys );
523                        for( int i=0; i<keys.length; i++ ) {
524                                list.add( new HybsEntry( keys[i],getAttribute( keys[i] ) ) );
525                        }
526                }
527                return list.toArray( new HybsEntry[list.size()] );
528        }
529
530        /**
531         * UserInfoの属性文字列を削除します。
532         *
533         * @param       key     キー
534         * @param       save    ユーザー永続化情報(GE20)から情報を削除するか
535         */
536        public void removeAttribute( final String key, final boolean save ) {
537                removeAttribute( key, save, false );
538        }
539
540        /**
541         * UserInfoの属性文字列を削除します。
542         *
543         * @og.rev 3.5.6.0 (2004/06/18) synchronized をattribute に行います。
544         * @og.rev 5.3.6.0 (2011/06/01) ユーザー永続化情報(GE20)から削除するかのフラグを追加
545         *
546         * @param       key     キー
547         * @param       save    ユーザー永続化情報(GE20)から情報を削除するか
548         * @param       common  ユーザー永続化情報(GE20)から情報削除時、全ユーザー公開情報を削除するか
549         */
550        private void removeAttribute( final String key, final boolean save, final boolean common ) {
551                synchronized( attribute ) {
552                        attribute.remove( key ) ;
553                }
554
555                if( save ) {
556                        deletePermanently( key, common );
557                }
558        }
559
560        /**
561         * ユーザー個別の画面オブジェクトのマップをセットします。
562         *
563         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
564         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
565         * @og.rev 4.1.1.0 (2008/01/29) 画面の格上げとお気に入りマップ作成はクラスUserAccessTableに依頼
566         * @og.rev 5.2.0.0 (2010/09/01) アクセス禁止アドレスによる不正アクセス防止機能追加
567         *
568         * @param       newGuiMap                       画面オブジェクトのマップ
569         * @param       newForbidAddrSet        アクセス禁止アドレスセット
570         */
571        public void setGUIMap( final Map<String,GUIInfo> newGuiMap, final Set<String> newForbidAddrSet ) {
572                if( newGuiMap != null ) {
573                        synchronized( guiLock ) {
574                                guiMap = newGuiMap ;
575                                forbidAddrSet = newForbidAddrSet;
576                                favoriteGuiMap = UserAccessTable.makeAccessDB( guiMap,systemId,userID,lang );
577                                isInfoSet = true;
578                        }
579                }
580        }
581
582        /**
583         * ユーザー個別の画面オブジェクトを取得します。
584         * アクセスできない画面IDが指定されたときは、null が返ります。
585         *
586         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
587         * @og.rev 5.2.0.0 (2010/09/01) guiMap の null 判定を追加
588         *
589         * @param       gamenId 画面ID
590         *
591         * @return      画面オブジェクト
592         */
593        public GUIInfo getGUIInfo( final String gamenId ) {
594                synchronized( guiLock ) {
595                        if( guiMap != null) {                                           // 5.2.0.0 (2010/09/01) guiMap の null 判定
596                                return guiMap.get( gamenId );
597                        }
598                        else {
599                                return null;                                                    // 5.2.0.0 (2010/09/01) 
600                        }
601                }
602        }
603
604        /**
605         * ユーザー個別の画面オブジェクトのマップを取得します。
606         *
607         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
608         * @og.rev 5.2.0.0 (2010/09/01) guiMap の null 判定を追加
609         *
610         * @return      画面オブジェクトの配列
611         */
612        public GUIInfo[] getGUIInfos() {
613                synchronized( guiLock ) {
614                        if( guiMap != null) {                                           // 5.2.0.0 (2010/09/01) guiMap の null 判定
615                                return guiMap.values().toArray( new GUIInfo[ guiMap.size() ] ) ;
616                        }
617                        else {
618                                return null;                                                    // 5.2.0.0 (2010/09/01) 
619                        }
620                }
621        }
622
623        /**
624         * アクセスが許可されているアドレスかどうかをチェックします。
625         *
626         * チェックの方法は、ブラックリスト方式です。
627         * 画面リソースに登録された一覧の内、そのユーザーが許可されていないアドレスに
628         * 対してのみfalseが返ります。
629         * 画面リソースに登録されていないアドレスや、アドレスにURLの区切り文字(/)が
630         * 含まれている場合はチェックされません。(trueが返ります)
631         *
632         * @og.rev 5.2.0.0 (2010/09/01) 新規追加
633         *
634         * @param addr チェック対象のアドレス
635         *
636         * @return アクセスが許可されているアドレスかどうか
637         */
638        public boolean isValidAddr( final String addr ) {
639                synchronized( guiLock ) {
640                        return forbidAddrSet == null || !forbidAddrSet.contains( addr ) ;
641                }
642        }
643
644        /**
645         * ユーザー個別のお気に入り画面オブジェクトのマップを取得します。
646         *
647         * @og.rev 4.1.1.0 (2008/01/31) 新規追加
648         *
649         * @return      お気に入り画面オブジェクトのマップ
650         */
651        public Map<String,FavoriteGUIData> getFavoriteMap() {
652                return favoriteGuiMap;
653        }
654
655        /**
656         * 画面オブジェクトのマップがセット済みかどうかを取得します。
657         *
658         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
659         *
660         * @return 画面オブジェクトのマップがセット済みかどうか(true:セット済み / false:未セット)
661         */
662        public boolean isGUIInfoSet() {
663                return isInfoSet ;
664        }
665
666        /**
667         * 指定のユーザーロールに対する最終的なアクセス条件を取得します。
668         * アクセス条件は、複数あるユーザーロールの中で、最大のアクセス条件を算出します。
669         * 例えば、AAA(-r)|BBB(-w)|CCC(mr) の3つのロール/モードが設定されている場合、
670         * ユーザーが、AAA だけの場合は、-r ですが、AAA|BBB を持っている場合は、-w になります。
671         * さらに、BBB|CCC と持っている場合は、(-w:書き込み許可)と(mr:メニューから読取許可)の
672         * 権限により、mw:メニューからの書き込み許可が与えられます。
673         * モード指定がある場合は、AND演算になります。
674         * 例えば、AAA(-r)|BBB(-w)|CCC(mr) と BBB|CCC(-r) の場合、(-r)+(-w)+(mr)*(-r)=-w に
675         * なります。ロールは、OR ですが、モードは、同一ロールでのAND になります。
676         * 実際には、メニュー表示の可否は、ポップアップ系によく用いられますので、上記のような
677         * 許可が実際にあるかどうかは不明ですが、すべてのモードのOR条件での結合になります。
678         *
679         * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
680         *
681         * @param       other   ロールモード
682         *
683         * @return アクセスビット
684         */
685        public byte getAccessBitMode( final RoleMode other ) {
686                return roleMode.getAccessBitMode( other );
687        }
688
689        /**
690         * このユーザーの権限で、指定のロールが許可されているかどうかを判定します。
691         *
692         * @og.rev 4.3.0.0 (2008/07/04) ロールモードマルチ対応
693         * @og.rev 4.3.0.1 (2008/08/11) ロールチェック時の引数間違い、是正
694         *
695         * @param       role    チェックを行うロール
696         *
697         * @return      アクセスできる(true)/出来ない(false)
698         */
699        public boolean isAccess( final String role ) {
700                if( role == null || role.length() == 0 ) {
701                        return true;
702                }
703
704                return  roleMode.getAccessBitMode( RoleMode.newInstance( role ) ) > 0 ;         // 4.3.0.1 (2008/08/11)
705        }
706
707        /**
708         * 初期化(クリア)します(org.opengion.fukurou.util.Cleanable の実装)。
709         * 画面オブジェクトのマップをクリアし、セット済みフラグを未セットに設定します。
710         * システムリソースの USE_ACCESS_TOKEI_TABLE が true の場合は、
711         * 画面アクセス状況を、アクセス統計テーブル(GE15)に書き込みます。
712         * ユーザー単位のパラメータは、システムリソースの USER_PARAMETER_SQL で
713         * 定義された値を検索して、取り込みます。
714         *
715         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
716         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
717         * @og.rev 5.6.8.1 (2013/09/13) lastRequestMap を ユーザー永続化情報(GE20) に書き込みます。
718         */
719        public void clear() {
720                if( useAccessTable && isInfoSet ) { saveGUIAccessInfo(); }
721                initLoad() ;
722
723                saveLastRequestValues();        // 5.6.8.1 (2013/09/13) lastRequestMap を ユーザー永続化情報(GE20) に書き込みます。
724        }
725
726        /**
727         * ユーザーパラメータを取得します。
728         * 画面オブジェクトのマップをクリアし、セット済みフラグを未セットに設定します。
729         * ユーザー単位のパラメータは、システムリソースの USER_PARAMETER_SQL で
730         * 定義された値を検索して、取り込みます。
731         *
732         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
733         */
734        private void initLoad() {
735
736                // ユーザーパラメータの取得
737                if( QUERY_PARAM != null && QUERY_PARAM.length() > 0 ) {
738                        String[] args = new String[] { systemId,userID };
739                        // 画面ID,操作,プログラムID
740                        if( appInfo != null ) {
741                                // 画面ID,操作,プログラムID
742                                appInfo.setModuleInfo( "UserInfo",null,"initLoad" );
743                        }
744                        String[][] vals = DBUtil.dbExecute( QUERY_PARAM,args,appInfo,DBID );
745
746                        synchronized( paramMap ) {
747                                paramMap.clear();
748                                for( int i=0; i<vals.length; i++ ) {
749                                        String key   = vals[i][0];
750                                        String val   = vals[i][1];
751                                        if( val != null && val.length() == 0 ) { continue; }
752                                        paramMap.put( key,val );
753                                }
754                        }
755                }
756        }
757
758        /**
759         * ユーザー永続化情報(GE20)からDBに保存されたUserInfoのパラメーターを取得します。
760         *
761         * ここでは、キーの先頭が、LAST_REQUEST_DATA_SUFIX(="LAST_REQUEST_")文字列が、
762         * 付いている物だけ lastRequestMap マップに設定します。(分けて管理します)
763         *
764         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
765         * @og.rev 5.6.8.1 (2013/09/13) setAttribute メソッドではなく、直接 Mapに登録します。
766         * @og.rev 5.7.2.2 (2014/01/24) 値が null、またはゼロ文字列の場合でも処理します。(5.6.8.1 以前に戻します)
767         *
768         * ※ コンストラクタのみで呼ばれるため、synchronized は入れていません。
769         * @see         #LAST_REQUEST_DATA_SUFIX
770         */
771        private void dbLoad() {
772                // ユーザー永続化情報(GE20)テーブル読み込み
773                String[] argsGe20 = new String[] { systemId,userID,roles };
774                String[][] valsGe20 = DBUtil.dbExecute( QUERY_GE20,argsGe20,appInfo,DBID );
775
776                for( int i=0; i<valsGe20.length; i++ ) {
777                        // 4.3.4.0 (2008/12/01) ユーザー永続化情報(GE20)から読み込んでいるので、当然保存しない
778                        String key = valsGe20[i][0];
779                        String val = valsGe20[i][1];
780                        if( key != null && key.length() > 0 ) {
781                                if( key.startsWith( LAST_REQUEST_DATA_SUFIX ) ) {
782                                        // val が null かどうかは問わない
783                                        lastRequestMap.put( key.substring( LAST_REQUEST_DATA_SUFIX.length() ) , val );
784                                }
785                                else {
786                                        // val が null の場合は、登録しない。
787                                        // 5.7.2.2 (2014/01/24) 値が null、またはゼロ文字列の場合でも処理します。(5.6.8.1 以前に戻します)
788                                                attribute.put( key,val ) ;
789                                }
790                        }
791                }
792        }
793
794        /**
795         * 属性一覧からEDIT設定情報をオブジェクト化し、画面ID毎のマップに登録します。
796         *
797         * ※ コンストラクタのみで呼ばれるため、synchronized は入れていません。
798         *
799         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
800         */
801        private void makeEditConfigMap() {
802                String[] keys = attribute.keySet().toArray( new String[0] );
803                String[][] keySet = DBEditConfig.getKeySet( keys );
804                if( keySet != null ) {
805                        for( String[] set : keySet ) {
806                                String guikey = set[0];
807                                String editName = set[1];
808                                String[] editKeys = DBEditConfig.getEditKeys( guikey, editName );
809                                String[] editVals = new String[editKeys.length];
810                                for( int i=0; i<editKeys.length; i++ ) {
811                                        editVals[i] = attribute.get( editKeys[i] );
812                                }
813                                editMgr.addEditConfig( guikey, editName, new DBEditConfig( editVals ) );
814                        }
815                }
816        }
817
818        /**
819         * 引数の画面で登録されているエディット設定を配列で返します。
820         * 返される配列は、エディット名順にソートされた状態で返されます。
821         *
822         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
823         *
824         * @param guikey 画面ID
825         *
826         * @return エディット設定(配列)
827         */
828        public DBEditConfig[] getEditConfigs( final String guikey ) {
829                return editMgr.getEditConfigs( guikey );
830        }
831
832        /**
833         * 画面ID、エディット名よりエディット設定オブジェクトを返します。
834         * また、ここで指定されたエディット名がこの画面での選択済みエディットとして登録されます。
835         *
836         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
837         *
838         * @param guikey 画面ID
839         * @param editName エディット名
840         *
841         * @return エディット配列
842         */
843        public DBEditConfig getEditConfig( final String guikey, final String editName ) {
844                if( editName != null ) {
845                        String selEditName = getSelectedEdit( guikey );
846                        if( !editName.equals( selEditName ) ) {
847                                setSelectedEdit( guikey, editName );
848                        }
849                }
850        //      else {
851        //              setSelectedEdit( guikey, null );
852        //      }
853                return editMgr.getEditConfig( guikey, editName );
854        }
855
856        /**
857         * 指定の画面ID、エディット名でエディット設定オブジェクトを追加します。
858         * 既に登録されている場合は、既存のエディット情報を更新します。
859         *
860         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
861         * @og.rev 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
862         *
863         * @param guikey 画面ID
864         * @param editName エディット名
865         * @param config エディット設定オブジェクト
866         */
867        public void addEditConfig( final String guikey, final String editName, final DBEditConfig config ) {
868                if( config == null ) { return; }
869
870                boolean isCommon = config.isCommon();
871                String[] editKeys = DBEditConfig.getEditKeys( guikey, editName );
872                String[] editVals = config.getEditVals();
873
874                // 個別設定の場合、同じキーで共通情報が存在していた場合はエラーとする。
875                if( !isCommon && isExistValue( editKeys[0], "*", "*" ) ) {
876                        String errMsg = "同じ編集名で共通設定されているため個別編集を保存できません。";
877                        throw new HybsSystemException( errMsg );        // 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
878                }
879                // 共通設定の場合、同じキーで個別情報が存在していた場合はエラーとする。
880                if( isCommon && isExistValue( editKeys[0], userID, "*" ) ) {
881                        String errMsg = "同じ編集名で個別設定されているため共通編集を保存できません。";
882                        throw new HybsSystemException( errMsg );        // 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
883                }
884
885                editMgr.addEditConfig( guikey, editName, config );
886                for( int i=0; i<editKeys.length; i++ ) {
887                        if( editVals[i] != null && editVals[i].length() > 0 ) {
888                                setAttribute( editKeys[i], editVals[i], true, isCommon );
889                        }
890                        else {
891                                removeAttribute( editKeys[i], true, isCommon );
892                        }
893                }
894        }
895
896        /**
897         * 指定の画面ID、エディット名のエディット設定を削除します。
898         *
899         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
900         * @og.rev 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
901         *
902         * @param guikey 画面ID
903         * @param editName エディット名
904         */
905        public void deleteEditConfig( final String guikey, final String editName ) {
906                DBEditConfig config = editMgr.deleteEditConfig( guikey, editName );
907                if( config != null ) {
908                        boolean isCommon = config.isCommon();
909                        String[] editKeys = DBEditConfig.getEditKeys( guikey, editName );
910                        // エディット設定が存在しない場合エラー。
911                        if( !isExistValue( editKeys[0], ( isCommon ? "*" : userID ), "*" ) ) {
912                                String errMsg = "エディット設定が存在しません。";
913                                throw new HybsSystemException( errMsg );        // 5.7.1.2 (2013/12/20) msg ⇒ errMsg 変更
914                        }
915                        for( int i=0; i<editKeys.length; i++ ) {
916                                removeAttribute( editKeys[i], true, isCommon );
917                        }
918                }
919
920        //      if( editName != null ) {
921        //              String selEditName = getSelectedEdit( guikey );
922        //              if( !editName.equals( selEditName ) ) {
923        //                      setSelectedEdit( guikey, null );
924        //              }
925        //      }
926        }
927
928        /**
929         * 指定の画面IDに対して選択済みのエディット名を登録します。
930         *
931         * なお、メモリやDBへの書き込みを考慮し、editName が null か、
932         * ゼロ文字列 の場合は、登録しません。
933         *
934         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
935         * @og.rev 5.7.2.2 (2014/01/24) 引数の editName が null か、ゼロ文字列 の場合は、登録しません。
936         *
937         * @param guikey 画面ID
938         * @param editName エディット名
939         */
940        public void setSelectedEdit( final String guikey, final String editName ) {
941                if( editName != null && editName.length() > 0 ) {       // 5.7.2.2 (2014/01/24)
942                        setAttribute( "EDIT_NAME_SELECTED_" + guikey, editName, true );
943                }
944        }
945
946        /**
947         * 指定の画面IDに対して選択済みのエディット名を返します。
948         *
949         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
950         *
951         * @param guikey 画面ID
952         *
953         * @return 選択済みエディット名
954         */
955        public String getSelectedEdit( final String guikey ) {
956                return getAttribute( "EDIT_NAME_SELECTED_" + guikey );
957        }
958
959        /**
960         * 最後に使用されたリクエスト変数の値を、Mapを読み取って登録します。
961         *
962         * 読み取り対象は、先に lastRequestMap に登録済みのキーだけです。
963         * そのため、{&#064;LAST.XXXX} で値を要求されたときに、キーが
964         * 登録されていない場合は、キーだけ(値 nullで)登録しておきます。
965         *
966         * @og.rev 5.6.8.1 (2013/09/13) 新規追加
967         *
968         * @param reqMap リクエスト変数のMap
969         */
970        public void setLastRequestMap( final Map<String,String[]> reqMap ) {
971                if( reqMap != null ) {
972                        synchronized( lastRequestMap ) {
973                                for( String key : lastRequestMap.keySet() ) {
974                                        String[] vals = reqMap.get( key );
975                                        if( vals != null ) {
976                                                String val = null;
977                                                for( int i=0; i<vals.length; i++ ) {
978                                                        val = vals[i];
979                                                        if( ! "0".equals( val ) ) { break; }    // チェックボックス対応
980                                                }
981                                                lastRequestMap.put( key, val );                         // val は、null もあり得る。
982                                        }
983                                }
984                        }
985                }
986        }
987
988        /**
989         * 最後に使用されたリクエスト変数の値を、設定します。
990         *
991         * この処理は、{&#064;LAST.XXXX} は、リクエスト値があれば、それが優先的に
992         * 使われます。
993         *
994         * @og.rev 5.6.8.1 (2013/09/13) 新規追加
995         *
996         * @param  key リクエストキー
997         * @param  val 設定値
998         */
999        public void setLastRequestValue( final String key,final String val ) {
1000                if( key != null && key.length() > 0) {
1001                        synchronized( lastRequestMap ) {
1002                                lastRequestMap.put( key, val );
1003                        }
1004                }
1005        }
1006
1007        /**
1008         * 最後に使用されたリクエスト変数の値を、取得します。
1009         *
1010         * 画面で簡素に使用できるように、少し特殊な処理を行います。
1011         * query 画面で {&#064;LAST.XXXX} を呼ぶと、lastRequestMap にキーがなければ、
1012         * キーだけ先に追加します。あれば、値を取得するだけです。
1013         * そして、result画面で command="NEW" の場合のみ、リクエスト情報のMapから、
1014         * lastRequestMap に持っているキーで(NULLでない場合は)上書きセットします。
1015         * キャッシュ量を減らすことと、処理の対象キーを減らす意味を持っています。
1016         *
1017         * @og.rev 5.6.8.1 (2013/09/13) 新規追加
1018         *
1019         * @param  key リクエストキー
1020         * @return 設定値
1021         */
1022        public String getLastRequestValue( final String key ) {
1023                String rtn = null;
1024                if( key != null && key.length() > 0) {
1025                        synchronized( lastRequestMap ) {
1026                                if( lastRequestMap.containsKey( key ) ) {       // キーを持っているかどうかを判定
1027                                        rtn = lastRequestMap.get( key );
1028                                }
1029                                else {
1030                                        lastRequestMap.put( key, null );                // キーだけ登録しておく。
1031                                }
1032                        }
1033                }
1034                return rtn ;
1035        }
1036
1037        /**
1038         * lastRequestMap を ユーザー永続化情報(GE20) に書き込みます。
1039         *
1040         * clear() 処理が実行された場合に、まとめて ユーザー永続化情報(GE20) に書き込みます。
1041         * タイミング的には、saveGUIAccessInfo() メソッドと同じですが、saveGUIAccessInfo() は、
1042         * 書き込む条件( useAccessTable && isInfoSet ) があります。
1043         * セーブする時には、他の属性と区別するため、接頭語 LAST_REQUEST_DATA_SUFIX(="LAST_REQUEST_") を
1044         * キーに付けて渡します。
1045         * 
1046         * 読み取りは、dbLoad() で、attribute と同じタイミングで、コンストラクタで、行います。
1047         *
1048         * @og.rev 5.6.8.1 (2013/09/13) 新規追加
1049         *
1050         * @see         #clear()
1051         * @see         #dbLoad()
1052         */
1053        private void saveLastRequestValues() {
1054                int cnt = 0;
1055                synchronized( lastRequestMap ) {
1056                        for( String key : lastRequestMap.keySet() ) {
1057                                String val = lastRequestMap.get( key );
1058                                // 内部処理的には冗長だが、実行頻度が少ないので、許す。
1059                                savePermanently( LAST_REQUEST_DATA_SUFIX + key,val,false );
1060                        }
1061                        cnt = lastRequestMap.size();
1062                }
1063                System.out.println( "  [" + userID + "] 最終リクエスト情報({@LAST.XXXX})を、(GE20)に、[" + cnt + "]件、登録しました。" );
1064        }
1065
1066        /**
1067         * アクセスログ取得の為,ApplicationInfoオブジェクトを返します。
1068         *
1069         * @og.rev 3.8.7.0 (2006/12/15) 新規追加
1070         *
1071         * @param       gamenId 実行中の画面ID
1072         * @param       prgId   実行中のプログラムID
1073         *
1074         * @return      ApplicationInfoオブジェクト
1075         */
1076        public ApplicationInfo getApplicationInfo( final String gamenId,final String prgId ) {
1077                if( appInfo != null ) {
1078                        // 画面ID,操作,プログラムID
1079                        appInfo.setModuleInfo( gamenId,null,prgId );
1080                }
1081                return appInfo;
1082        }
1083
1084        /**
1085         * 自然比較メソッド
1086         * インタフェース Comparable の 実装です。
1087         * ユーザーの順序は、ユーザーID そのものの順序であらわされます。
1088         * 同一ユーザーの場合は,ログインタイムの順番になります。
1089         *
1090         * @og.rev 5.1.8.0 (2010/07/01) UserSummary の Comparable を型設定
1091         *
1092         * @param       object  比較対象のObject
1093         *
1094         * @return      このオブジェクトが指定されたオブジェクトより小さい場合は負の整数、等しい場合はゼロ、大きい場合は正の整数
1095         */
1096        @Override
1097        public int compareTo( final UserSummary object ) {
1098                int test1 = userID.compareTo( object.getUserID() );
1099                if( test1 == 0 ) {
1100                        test1 = (int)( loginTime - object.getLoginTime() ) ;
1101                }
1102                return test1;
1103        }
1104
1105        /**
1106         * このオブジェクトと他のオブジェクトが等しいかどうかを示します。
1107         * インタフェース Comparable の 実装に関連して、再定義しています。
1108         * ユーザーは、ユーザーIDが等しく、かつ ログイン時刻が同一の場合に、
1109         * 等しいと判断されます。
1110         *
1111         * @param   object 比較対象の参照オブジェクト
1112         *
1113         * @return      引数に指定されたオブジェクトとこのオブジェクトが等しい場合は true、そうでない場合は false
1114         */
1115        @Override
1116        public boolean equals( final Object object ) {
1117                if( object instanceof UserInfo ) {
1118                        return userID.equals( ((UserInfo)object).getUserID()  )
1119                                        && loginTime == ( ((UserInfo)object).getLoginTime() );
1120                }
1121                return false ;
1122        }
1123
1124        /**
1125         * オブジェクトのハッシュコード値を返します。
1126         * このメソッドは、java.util.Hashtable によって提供されるような
1127         * ハッシュテーブルで使用するために用意されています。
1128         * equals( Object ) メソッドをオーバーライトした場合は、hashCode() メソッドも
1129         * 必ず 記述する必要があります。
1130         * ここでは、ログイン時刻(long 値)の上位 32 ビットと下位 32 ビットの排他的論理和
1131         * を求めています。
1132         * (int)(this.longValue()^(this.longValue()&gt;&gt;&gt;32))
1133         *
1134         * ※ hashCode の 同一オブジェクトには同一ハッシュコードという規則と
1135         *    発生頻度,ランダム性を考慮すれば、ログイン時刻そのもの(long)の
1136         *    ハッシュコードでも運用上は全く問題ないと考えられます。
1137         *
1138         * @og.rev 3.5.6.0 (2004/06/18) 新規追加
1139         *
1140         * @return  このオブジェクトのハッシュコード値
1141         *
1142         */
1143        @Override
1144        public int hashCode() {
1145                return hashcode ;
1146        }
1147
1148        /**
1149         * オブジェクトの識別子として,詳細なユーザー情報を返します。
1150         *
1151         * @return  詳細なユーザー情報
1152         */
1153        @Override
1154        public String toString() {
1155                StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
1156                rtn.append( "userID   :" ).append( userID        ).append( HybsSystem.CR );
1157                rtn.append( "lang     :" ).append( lang          ).append( HybsSystem.CR );
1158                rtn.append( "jname    :" ).append( jname         ).append( HybsSystem.CR );
1159                rtn.append( "roles    :" ).append( roles         ).append( HybsSystem.CR );
1160                rtn.append( "IPAddress:" ).append( ipAddress ).append( HybsSystem.CR );
1161                rtn.append( "loginTime:" ).append( loginTime ).append( HybsSystem.CR );
1162                return rtn.toString();
1163        }
1164
1165        /**
1166         * ユーザー個別の画面オブジェクトの明細情報をアクセス統計テーブル(GE15)に登録します。
1167         *
1168         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
1169         * @og.rev 4.0.0.0 (2005/01/31) 新規追加
1170         * @og.rev 4.0.0.0 (2007/10/05) SQLServer 互換性の為、SUBSTRB を廃止します。
1171         * @og.rev 4.1.1.0 (2008/01/30) ユーザーアクセス画面管理テーブルに画面の最終アクセス時間を更新
1172         * @og.rev 5.0.2.0 (2009/11/01) 作成・更新日付がセットされていないバグを修正
1173         * @og.rev 5.2.3.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
1174         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
1175         */
1176        private void saveGUIAccessInfo() {
1177        //      if( !useAccessTable || !isInfoSet ) { return ; }
1178
1179                final GUIInfo[] infos ;
1180                synchronized( guiLock ) {
1181                        infos = getGUIInfos() ;
1182                        guiMap = null;
1183                        isInfoSet = false;
1184                }
1185
1186                long crntTime = System.currentTimeMillis();
1187
1188                String[] names = new String[] { "SYSTEM_ID","USERID","USERADRS","HOSTADRS","GUIKEY","DYLOGIN","DYLOGOUT",
1189                                                                                "USED_TIME","CNT_ACCESS","CNT_ERROR","CNT_READ","CNT_WRITE",
1190                                                                                "TM_TOTAL_QUERY","TM_MAX_QUERY","MAX_QUERY","FGJ","DYSET","DYUPD","USRSET","USRUPD","PGUPD" };
1191                String[] values = new String[names.length];
1192
1193                values[C_SYSTEM_ID              ] = HybsSystem.sys( "SYSTEM_ID" );
1194                values[C_USERID                 ] = userID;
1195                values[C_USERADRS               ] = ipAddress;
1196                values[C_HOSTADRS               ] = HybsSystem.sys( "HOST_ADRS" );
1197                values[C_GUIKEY                 ] = "";
1198                values[C_DYLOGIN                ] = HybsSystem.getDate( loginTime,"yyyyMMddHHmmss" );
1199                values[C_DYLOGOUT               ] = HybsSystem.getDate( "yyyyMMddHHmmss" );
1200                values[C_USED_TIME              ] = String.valueOf( Math.round( (crntTime-usedTime) / 1000.0d ) );      // 秒に変換
1201                values[C_CNT_ACCESS             ] = "0";
1202                values[C_CNT_ERROR              ] = "0";
1203                values[C_CNT_READ               ] = "0";
1204                values[C_CNT_WRITE              ] = "0";
1205                values[C_TM_TOTAL_QUERY ] = "0";
1206                values[C_TM_MAX_QUERY   ] = "0";
1207                values[C_MAX_QUERY              ] = "";
1208                values[C_FGJ                    ] = "1";
1209                values[C_DYSET                  ] = HybsSystem.getDate( "yyyyMMddHHmmss" );
1210                values[C_DYUPD                  ] = HybsSystem.getDate( "yyyyMMddHHmmss" );
1211                values[C_USRSET                 ] = "userInfo";
1212                values[C_USRUPD                 ] = "userInfo";
1213                values[C_PGUPD                  ] = "userInfo";
1214
1215                usedTime = crntTime ;
1216
1217                DBSimpleTable dbTable = new DBSimpleTable( names );
1218                // 画面ID,操作,プログラムID
1219                getApplicationInfo( "UserInfo","saveGUI" );
1220                dbTable.setApplicationInfo( appInfo );  // 3.8.7.0 (2006/12/15)
1221                dbTable.setConnectionID( DBID );                // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
1222                dbTable.setTable( "GE15" );
1223                // 4.0.0.0 (2007/10/05) SQLServer 互換性の為、CLOB化します。
1224        //      dbTable.addConstrain( names[C_MAX_QUERY],"SUBSTRB(?,1,4000)" );
1225
1226                boolean okFlag = false;
1227                try {
1228                        dbTable.startInsert();
1229
1230                        // UserInfo に関する情報の登録
1231                        dbTable.execute( values );
1232
1233                        // GUIInfo に関する情報の登録
1234                        if( infos != null ) {
1235                                values[C_USED_TIME] = "0";      // USED_TIME をクリアしておきます。
1236                                String logoutTime = HybsSystem.getDate( "yyyyMMddHHmmss" );
1237                                for( int i=0; i<infos.length; i++ ) {
1238                                        GUIAccessCount access = infos[i].getGUIAccessCount();
1239                                        int cnt = access.getAccessCount();
1240                                        if( cnt > 0 ) {
1241                                                values[C_GUIKEY                 ] = access.getKey();
1242                                                values[C_CNT_ACCESS             ] = String.valueOf( cnt );
1243                                                values[C_CNT_ERROR              ] = String.valueOf( access.getErrorCount() );
1244                                                values[C_CNT_READ               ] = String.valueOf( access.getReadCount() );
1245                                                values[C_CNT_WRITE              ] = String.valueOf( access.getWriteCount() );
1246                                                values[C_TM_TOTAL_QUERY ] = String.valueOf( access.getQueryTime() );
1247                                                values[C_TM_MAX_QUERY   ] = String.valueOf( access.getMaxQueryTime() );
1248                                                values[C_MAX_QUERY              ] = access.getMaxQuery();
1249        //                                      dbTable.addValues( values );
1250                                                dbTable.execute( values );
1251                                                // 4.1.1.0(2008/01/28)画面アクセス時間の更新
1252                                                // 5.2.3.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
1253                                                String keys = infos[i].getNextGuiKeys();
1254                                                UserAccessTable.updateLastAccessTime( systemId,userID,access.getKey(),logoutTime,keys );
1255                                        }
1256                                }
1257                        }
1258                        okFlag = true;
1259                }
1260                catch (SQLException ex) {
1261                        LogWriter.log( "  [" + userID + "] アクセス統計テーブル(GE15)登録時にエラーが発生しました" );
1262                        LogWriter.log( ex.getMessage() );
1263                }
1264                finally {
1265                        int cnt = dbTable.close( okFlag );
1266                        System.out.println( "  [" + userID + "] アクセス統計テーブル(GE15)に、[" + cnt + "]件、追加しました。" );
1267                }
1268        }
1269
1270        /**
1271         * userInfoにセットされた値/キーをDBに登録します。
1272         * 既にキーが存在している場合は、既存データを更新し、なければ追加します。
1273         *
1274         * @og.rev 5.3.6.0 (2011/06/01) 全ユーザー情報として保存できるように対応
1275         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
1276         *
1277         * @param key キー
1278         * @param value 値
1279         * @param isCommon ユーザーID='*'(全ユーザー公開)として登録するかどうか
1280         */
1281        private void savePermanently( final String key, final String value, final boolean isCommon ) {
1282
1283                // 追加変更時に共通でセットされる値を設定
1284                String[] names = new String[] { "SYSTEM_ID","USERID","ROLES","PARAM_ID","PARAM","KBSET"
1285                                                                                ,"FGJ","DYSET","DYUPD","USRSET","USRUPD","PGUPD" };
1286                String[] values = new String[names.length];
1287                values[C_GE20_SYSTEM_ID ] = HybsSystem.sys( "SYSTEM_ID" );
1288                values[C_GE20_USERID    ] = ( isCommon ? "*" : userID );
1289                values[C_GE20_ROLES             ] = GE20_ROLES;
1290                values[C_GE20_PARAM_ID  ] = key;
1291                values[C_GE20_PARAM             ] = value;
1292                values[C_GE20_KBSET             ] = String.valueOf( GE20_KBSET_WRITABLE );
1293                values[C_GE20_FGJ               ] = "1";
1294                values[C_GE20_DYSET             ] = HybsSystem.getDate( "yyyyMMddHHmmss" );
1295                values[C_GE20_DYUPD             ] = HybsSystem.getDate( "yyyyMMddHHmmss" );
1296                values[C_GE20_USRSET    ] = userID;
1297                values[C_GE20_USRUPD    ] = userID;
1298                values[C_GE20_PGUPD     ] = "UserInfo";
1299
1300                // 画面ID,操作,プログラムID
1301                getApplicationInfo( "UserInfo","registValueToDB" );
1302
1303                DBSimpleTable dbTable = new DBSimpleTable( names );
1304                dbTable.setApplicationInfo( appInfo );  // 3.8.7.0 (2006/12/15)
1305                dbTable.setConnectionID( DBID );                // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
1306                dbTable.setTable( "GE20" );
1307
1308                boolean okFlag = false;
1309                try {
1310                        if( isExistValue( key, ( isCommon ? "*" : userID ), GE20_ROLES ) ) {
1311                                String where = "SYSTEM_ID = [SYSTEM_ID] and USERID = [USERID] and ROLES = [ROLES] and PARAM_ID = [PARAM_ID] and FGJ='1'";
1312                                dbTable.setWhere( where );
1313                                dbTable.startUpdate();
1314                        }
1315                        else {
1316                                dbTable.startInsert();
1317                        }
1318                        dbTable.execute( values );
1319                        okFlag = true;
1320                }
1321                catch ( SQLException ex ) {
1322                        throw new HybsSystemException( "ユーザー永続化情報(GE20)設定時にエラーが発生しました", ex );
1323                }
1324                finally {
1325                        dbTable.close( okFlag );
1326                }
1327        }
1328
1329        /**
1330         * userInfoから削除された値/キーをDBからも削除します。
1331         *
1332         * @og.rev 5.3.6.0 (2011/06/01) 新規追加
1333         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
1334         *
1335         * @param key キー
1336         * @param isCommon ユーザーID='*'(全ユーザー公開)から削除するかどうか
1337         */
1338        private void deletePermanently( final String key, final boolean isCommon ) {
1339
1340                // 追加変更時に共通でセットされる値を設定
1341                String[] names = new String[] { "SYSTEM_ID","USERID","ROLES","PARAM_ID" };
1342                String[] values = new String[names.length];
1343                values[C_GE20_SYSTEM_ID ] = HybsSystem.sys( "SYSTEM_ID" );
1344                values[C_GE20_USERID    ] = ( isCommon ? "*" : userID );
1345                values[C_GE20_ROLES             ] = GE20_ROLES;
1346                values[C_GE20_PARAM_ID  ] = key;
1347
1348                // 画面ID,操作,プログラムID
1349                getApplicationInfo( "UserInfo","deleteValueFromDB" );
1350
1351                DBSimpleTable dbTable = new DBSimpleTable( names );
1352                dbTable.setApplicationInfo( appInfo );
1353                dbTable.setConnectionID( DBID );                // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
1354                dbTable.setTable( "GE20" );
1355
1356                boolean okFlag = false;
1357                try {
1358                        String where = "SYSTEM_ID = [SYSTEM_ID] and USERID = [USERID] and ROLES = [ROLES] and PARAM_ID = [PARAM_ID] and FGJ='1'";
1359                        dbTable.setWhere( where );
1360                        dbTable.startDelete();
1361                        dbTable.execute( values );
1362                        okFlag = true;
1363                }
1364                catch ( SQLException ex ) {
1365                        throw new HybsSystemException( "ユーザー永続化情報(GE20)削除時にエラーが発生しました", ex );
1366                }
1367                finally {
1368                        dbTable.close( okFlag );
1369                }
1370        }
1371
1372        /**
1373         * ユーザー永続化情報(GE20)に該当のキーが存在するかをチェックします。
1374         *
1375         * @og.rev 5.3.6.0 (2011/06/01) 全ユーザー情報として保存できるように対応
1376         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
1377         *
1378         * @param key キー
1379         * @param userid ユーザーID
1380         * @param roles ロール
1381         *
1382         * @return true:存在している/false:存在していない
1383         */
1384        private boolean isExistValue( final String key, final String userid, final String roles ) {
1385                String[] args = { HybsSystem.sys( "SYSTEM_ID" ), userid, roles, key };
1386
1387                // 画面ID,操作,プログラムID
1388                getApplicationInfo( "UserInfo","isExistValue" );
1389
1390                String[][] rtn = DBUtil.dbExecute( QUERY_GE20_KEY, args, appInfo, DBID );       // 5.5.5.1 (2012/08/07)
1391                if( rtn == null || rtn.length == 0 ) {
1392                        return false;
1393                }
1394                else if( rtn[0].length > 0 ) {
1395                        if( String.valueOf( GE20_KBSET_READONLY ).equals( rtn[0][0] ) ) {
1396                                throw new HybsSystemException( "読み取り専用情報のため、書き込みできません" );
1397                        }
1398                        else {
1399                                return true;
1400                        }
1401                }
1402                else {
1403                        throw new HybsSystemException( "ユーザー永続化情報(GE20)検索時にエラーが発生しました。" );
1404                }
1405        }
1406
1407        /**
1408         * 指定されたカラムキーに対応するデータの条件式を返します。
1409         *
1410         * @og.rev 4.4.0.0 (2009/08/02) 新規追加
1411         *
1412         * @param clm カラム名
1413         *
1414         * @return データの条件式
1415         */
1416        public String getDataCondition ( final String clm ) {
1417                return dataRole.getCondition( clm );
1418        }
1419
1420        /**
1421         * このユーザーでアクセスされた画面オブジェクトを設定します。
1422         *
1423         * これは、画面アクセスの履歴(順番)を管理する機能に使います。
1424         *
1425         * @og.rev 5.2.3.0 (2010/12/01) 新規追加
1426         *
1427         * @param guiInfo 画面オブジェクト
1428         */
1429        public void setAccessGui( final GUIInfo guiInfo ) {
1430                if( lastGuiInfo != null && guiInfo != null ) {
1431                        lastGuiInfo.setNextGuiKey( guiInfo.getKey() );
1432                }
1433                lastGuiInfo = guiInfo ;         // 最後にアクセスした GUIInfo を設定
1434        }
1435}