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.taglib;
017
018import org.opengion.hayabusa.resource.UserInfo;
019import org.opengion.hayabusa.db.DBTableModel;
020import org.opengion.hayabusa.db.Query;
021import org.opengion.hayabusa.db.QueryFactory;
022import org.opengion.fukurou.db.Transaction;
023import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
024import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
025
026import static org.opengion.fukurou.util.StringUtil.nval ;
027
028import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
029import java.util.Locale ;
030
031/**
032 * ユーザー情報を管理しているタグです。
033 *
034 * 設定した値は、{@USER.XXXX} 形式で 取り出すことができます。
035 * また、command 属性で 直接画面に値を書き出すことも可能です。
036 *
037 * 以下の値は UserInfo オブジェクトの項目から取得します。
038 * ・USER.JNAME     ユーザー日本語名称
039 * ・USER.ID        ユーザーID
040 * ・USER.IDNO      USER.ID が5Byte以上の時のみ先頭1文字を除いたユーザーID
041 * ・USER.INFO      ユーザー情報(ユーザーID:日本語名称)
042 * ・USER.LANG      言語
043 * ・USER.ROLES     ロール
044 * ・USER.IPADDRESS IPアドレス
045 * ・USER.LOGINTIME ログイン時刻
046 *
047 * 以下の値はあらかじめ、動的に作成されます。
048 * ・USER.YMD       8byte の今日のシステム日付
049 * ・USER.YMDH    14byte の今日のシステム日時
050 *
051 * それ以外は、外部より設定された値です。
052 *
053 * ※ このタグは、Transaction タグの対象です。
054 *
055 * @og.formSample
056 * ●形式:<og:userInfo command="[…]" key="[…]" value="[…]" />
057 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
058 *
059 * ●Tag定義:
060 *   <og:userInfo
061 *       command            【TAG】コマンド (SET,GET,NVLGET,REMOVE,SQL)をセットします(初期値:SET)
062 *       key                【TAG】UserInfo に登録するキーをセットします(予約語:JNAME,ID,PASSWD,IDNO,INFO,LANG,ROLE,IPADDRESS,LOGINTIME)
063 *       value              【TAG】UserInfo に登録する値をセットします
064 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
065 *       save               【TAG】UserInfo に登録した値を永続化するかを指定します(初期値:false)
066 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
067 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
068 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
069 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
070 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
071 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
072 *   >   ... Body ...
073 *   </og:userInfo>
074 *
075 * ●使用例
076 *      <og:userInfo
077 *         command       = "コマンド (SET,GET,NVLGET,REMOVE,SQL)をセットします(初期値:SET)。"
078 *         key           = "UserInfo に登録するキーをセットします(予約語:JNAME,ID,PASSWD,IDNO,INFO,LANG,ROLE,IPADDRESS,LOGINTIME)。"
079 *         value         = "UserInfo に登録する値をセットします。"
080 *         dbid          = "(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。"
081 *      >
082 *
083 * @og.group その他部品
084 *
085 * @version  4.0
086 * @author   Kazuhiko Hasegawa
087 * @since    JDK5.0,
088 */
089public class UserInfoTag extends CommonTagSupport {
090        /** このプログラムのVERSION文字列を設定します。   {@value} */
091        private static final String VERSION = "6.4.3.4 (2016/03/11)" ;
092        private static final long serialVersionUID = 643420160311L ;
093
094        /** command 引数に渡す事の出来る コマンド  セット {@value} */
095        public static final String CMD_SET   = "SET" ;
096        /** command 引数に渡す事の出来る コマンド  ゲット {@value} */
097        public static final String CMD_GET   = "GET" ;
098        /** command 引数に渡す事の出来る コマンド  ゲット {@value} */
099        public static final String CMD_REMOVE   = "REMOVE" ;
100        /** command 引数に渡す事の出来る コマンド  ゲット {@value} */
101        public static final String CMD_SQL   = "SQL" ;
102        // 3.5.5.3 (2004/04/09) 値が null の場合は、""(ゼロ文字列)を返すNVLGETを採用
103        /** command 引数に渡す事の出来る コマンド  NVLゲット {@value} */
104        public static final String CMD_NVLGET   = "NVLGET" ;
105
106        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
107        private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_SET , CMD_GET , CMD_NVLGET , CMD_REMOVE , CMD_SQL );
108
109        // 3.5.6.0 (2004/06/18) すべてを protected から private に変更します。
110        private String                  command         = CMD_SET;
111        private String                  key                     ;
112        private String                  value           ;
113        private transient DBTableModel table;
114        // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
115        private String                  dbid            ;
116        private String                  sql                     ;
117        // 4.3.4.0 (2008/12/01) save属性追加
118        private boolean                 save            ;
119
120        /**
121         * デフォルトコンストラクター
122         *
123         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
124         */
125        public UserInfoTag() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
126
127        /**
128         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
129         *
130         * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
131         *
132         * @return      後続処理の指示
133         */
134        @Override
135        public int doStartTag() {
136                // 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
137                return useTag() && CMD_SQL.equals( command )
138                                        ? EVAL_BODY_BUFFERED                            // Body を評価する
139                                        : SKIP_BODY ;                                           // Body を評価しない
140        }
141
142        /**
143         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
144         *
145         * @og.rev 3.1.1.0 (2003/03/28) ボディの内容を取得する処理を、CommonTagSupport で行う。
146         * @og.rev 3.6.0.8 (2004/11/19) エラー発生時に確実にリリースされるように try finally 追加
147         * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。
148         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
149         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
150         * @og.rev 5.1.9.0 (2010/08/01) TransactionTag 対応。上位に TransactionTag があれば、そこからConnection をもらう。
151         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
152         * @og.rev 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
153         * @og.rev 6.3.1.1 (2015/07/10) BodyString,BodyRawStringは、CommonTagSupport で、trim() します。
154         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
155         * @og.rev 6.3.6.1 (2015/08/28) QueryFactory.close( Query ) 廃止。Queryはキャッシュしません。
156         *
157         * @return      後続処理の指示(SKIP_BODY)
158         */
159        @Override
160        public int doAfterBody() {
161                sql = getBodyString();
162
163                // 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
164                try( final Transaction tran = getTransaction() ) {
165                        final Query query = QueryFactory.newInstance();         // 4.0.0 (2005/01/31)
166                        query.setConnection( tran.getConnection( dbid ) );                      // 6.3.6.1 (2015/08/28)
167                        query.setResourceManager( getResource() );      // 4.0.0 (2005/01/31)
168                        query.setStatement( sql );
169                        query.execute();
170
171                        table = query.getDBTableModel();
172                        tran.commit();                          // 6.3.6.1 (2015/08/28)
173                }
174                return SKIP_BODY ;
175        }
176
177        /**
178         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
179         *
180         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
181         * @og.rev 3.5.5.3 (2004/04/09) 値が null の場合は、""(ゼロ文字列)を返すフラグを採用
182         * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
183         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
184         *
185         * @return      後続処理の指示
186         */
187        @Override
188        public int doEndTag() {
189                debugPrint();           // 4.0.0 (2005/02/28)
190                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
191                if( useTag() && check( command, COMMAND_SET ) ) {
192                        commandExec( command );
193
194                        if( CMD_GET.equals( command ) ) {
195                                jspPrint( value );
196                        }
197                        else if( CMD_NVLGET.equals( command ) ) {       // 3.5.5.3 (2004/04/09)
198                                jspPrint( nval(value,"") );
199                        }
200                }
201
202                return EVAL_PAGE ;
203        }
204
205        /**
206         * タグリブオブジェクトをリリースします。
207         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
208         *
209         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
210         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
211         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
212         * @og.rev 4.3.4.0 (2008/12/01) save属性対応
213         *
214         */
215        @Override
216        protected void release2() {
217                super.release2();
218                command         = CMD_SET;
219                key                     = null;
220                value           = null;
221                table           = null;
222                dbid            = null;
223                sql                     = null;
224                save            = false;
225        }
226
227        /**
228         * コマンドを実行します。
229         *
230         * コマンドは,HTMLから(get/post)指定されますので,setCommand()メソッドで
231         * 登録します。
232         * コマンドを登録すると同時に,実行も行ないます。
233         *
234         * @og.rev 3.5.5.3 (2004/04/09) 値が null の場合は、""(ゼロ文字列)を返すフラグを採用
235         *
236         * @param   command コマンド (public static final 宣言されている文字列)
237         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.UserInfoTag.CMD_GET">コマンド定数</a>
238         */
239        protected void commandExec( final String command ) {
240                if( CMD_SQL.equals( command ) ) { setSQLAttribute() ; }
241                else if( CMD_SET.equals(    command ) ) { setAttribute() ;    }
242                else if( CMD_GET.equals(    command ) ) { getAttribute() ;    }
243                else if( CMD_NVLGET.equals( command ) ) { getAttribute() ;    } // 3.5.5.3 (2004/04/09)
244                else if( CMD_REMOVE.equals( command ) ) { removeAttribute() ; }
245        }
246
247        /**
248         * UserInfoの文字列を登録します。
249         *
250         * @og.rev 4.3.4.0 (2008/12/01) GE20(ユーザー定数)へ登録するかのフラグを追加
251         *
252         */
253        private void setAttribute() {
254                setUserInfo( key, value, save );
255        }
256
257        /**
258         * UserInfoの文字列を作成します。
259         *
260         */
261        private void getAttribute() {
262                value = getUserInfo( key );
263        }
264
265        /**
266         * UserInfoの文字列を削除します。
267         *
268         * @og.rev 5.3.6.0 (2011/06/01) GE20(ユーザー定数)から削除するかのフラグを追加
269         */
270        private void removeAttribute() {
271                final UserInfo userInfo = getUser();
272                userInfo.removeAttribute( key, save );
273        }
274
275        /**
276         * UserInfoの文字列を指定のSQL文より作成します。
277         *
278         * @og.rev 4.3.4.0 (2008/12/01) GE20(ユーザー定数)へ登録するかのフラグを追加
279         *
280         */
281        private void setSQLAttribute() {
282                if( table == null || table.getRowCount() == 0 ) { return ; }
283
284                final int row    = 0;
285                final int clmCnt = table.getColumnCount();
286                for( int clm=0; clm<clmCnt; clm++ ) {
287                        final String clmkey = table.getColumnName( clm );
288                        final String clmval = table.getValue( row,clm );
289                        setUserInfo( clmkey, clmval, save );
290                }
291        }
292
293        /**
294         * 【TAG】コマンド (SET,GET,NVLGET,REMOVE,SQL)をセットします(初期値:SET)。
295         *
296         * @og.tag
297         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
298         * フィールド定数値のいずれかを、指定できます。
299         * 何も設定されない、または、null の場合は、"SET" が初期値にセットされます。
300         * SQL の場合、検索結果の戻り値が複数存在する場合は、最初の1件目のみ使用します。
301         *
302         * @param       cmd コマンド (public static final 宣言されている文字列)
303         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.UserInfoTag.CMD_SET">コマンド定数</a>
304         */
305        public void setCommand( final String cmd ) {
306                final String cmd2 = getRequestParameter( cmd );
307                if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
308        }
309
310        /**
311         * 【TAG】UserInfo に登録するキーをセットします(予約語:JNAME,ID,PASSWD,IDNO,INFO,LANG,ROLE,IPADDRESS,LOGINTIME)。
312         *
313         * @og.tag UserInfo に登録するキーをセットします。
314         *
315         * @param       inkey 登録するキー
316         */
317        public void setKey( final String inkey ) {
318                key = getRequestParameter( inkey ).toUpperCase(Locale.JAPAN);
319                if( key.startsWith( "USER." ) ) {
320                        key = key.substring( 5 );
321                }
322        }
323
324        /**
325         * 【TAG】UserInfo に登録する値をセットします。
326         *
327         * @og.tag UserInfo に登録する値をセットします。
328         *
329         * @param       val     登録値
330         */
331        public void setValue( final String val ) {
332                value = getRequestParameter( val );
333        }
334
335        /**
336         * 【TAG】UserInfo に登録した値を永続化するかを指定します(初期値:false)。
337         *
338         * @og.tag
339         * UserInfo に登録した値を永続化するかを指定します。
340         * trueが指定された場合、UserInfoに設定された値は、GE20(ユーザー定数)に保存され、
341         * UserInfoが再作成されるタイミングで自動的に復元されます。
342         * ここで、登録された値は、そのユーザーの全てのロールに対して有効となります。
343         * 初期値は、false(永続化しない)です。
344         *
345         * @param       sv      登録値を永続化するか
346         */
347        public void setSave( final String sv ) {
348                save = nval( getRequestParameter( sv ),save );
349        }
350
351        /**
352         * 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。
353         *
354         * @og.tag Queryオブジェクトを作成する時のDB接続IDを指定します。
355         *
356         * @param       id データベース接続ID
357         */
358        public void setDbid( final String id ) {
359                dbid = nval( getRequestParameter( id ),dbid );
360        }
361
362        /**
363         * このオブジェクトの文字列表現を返します。
364         * 基本的にデバッグ目的に使用します。
365         *
366         * @return このクラスの文字列表現
367         * @og.rtnNotNull
368         */
369        @Override
370        public String toString() {
371                return ToString.title( this.getClass().getName() )
372                                .println( "VERSION"                     ,VERSION        )
373                                .println( "command"                     ,command        )
374                                .println( "key"                         ,key            )
375                                .println( "value"                       ,value          )
376                                .println( "dbid"                        ,dbid           )
377                                .println( "sql"                         ,sql            )
378                                .println( "save"                        ,save           )
379                                .println( "Other..."    ,getAttributes().getAttribute() )
380                                .fixForm().toString() ;
381        }
382}