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.db.TransactionReal;
024
025import static org.opengion.fukurou.util.StringUtil.nval ;
026
027import java.util.Locale ;
028import java.io.ObjectOutputStream;
029import java.io.ObjectInputStream;
030import java.io.IOException;
031
032/**
033 * ユーザー情報を管理しているタグです。
034 *
035 * 設定した値は、{@USER.XXXX} 形式で 取り出すことができます。
036 * また、command 属性で 直接画面に値を書き出すことも可能です。
037 *
038 * 以下の値は UserInfo オブジェクトの項目から取得します。
039 * ・USER.JNAME     ユーザー日本語名称
040 * ・USER.ID        ユーザーID
041 * ・USER.IDNO      USER.ID が5Byte以上の時のみ先頭1文字を除いたユーザーID
042 * ・USER.INFO      ユーザー情報(ユーザーID:日本語名称)
043 * ・USER.LANG      言語
044 * ・USER.ROLES     ロール
045 * ・USER.IPADDRESS IPアドレス
046 * ・USER.LOGINTIME ログイン時刻
047 *
048 * 以下の値はあらかじめ、動的に作成されます。
049 * ・USER.YMD       8byte の今日のシステム日付
050 * ・USER.YMDH    14byte の今日のシステム日時
051 *
052 * それ以外は、外部より設定された値です。
053 *
054 * ※ このタグは、Transaction タグの対象です。
055 *
056 * @og.formSample
057 * ●形式:<og:userInfo command="[…]" key="[…]" value="[…]" />
058 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
059 *
060 * ●Tag定義:
061 *   <og:userInfo
062 *       command            【TAG】コマンド(SET,GET,NVLGET,REMOVE,SQL)をセットします(初期値:SET)
063 *       key                【TAG】UserInfo に登録するキーをセットします(予約語:JNAME,ID,PASSWD,IDNO,INFO,LANG,ROLE,IPADDRESS,LOGINTIME)
064 *       value              【TAG】UserInfo に登録する値をセットします
065 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
066 *       save               【TAG】UserInfo に登録した値を永続化するかを指定します
067 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
068 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
069 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:true)
070 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値: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 = "5.3.8.0 (2011/08/01)" ;
092
093        private static final long serialVersionUID = 538020110801L ;
094
095        /** command 引数に渡す事の出来る コマンド  セット {@value} */
096        public static final String CMD_SET   = "SET" ;
097        /** command 引数に渡す事の出来る コマンド  ゲット {@value} */
098        public static final String CMD_GET   = "GET" ;
099        /** command 引数に渡す事の出来る コマンド  ゲット {@value} */
100        public static final String CMD_REMOVE   = "REMOVE" ;
101        /** command 引数に渡す事の出来る コマンド  ゲット {@value} */
102        public static final String CMD_SQL   = "SQL" ;
103        // 3.5.5.3 (2004/04/09) 値が null の場合は、""(ゼロ文字列)を返すNVLGETを採用
104        /** command 引数に渡す事の出来る コマンド  NVLゲット {@value} */
105        public static final String CMD_NVLGET   = "NVLGET" ;
106
107        // 3.5.5.3 (2004/04/09) 値が null の場合は、""(ゼロ文字列)を返すNVLGETを採用
108        /** command 引数に渡す事の出来る コマンド リスト  */
109        private static final String[] COMMAND_LIST = new String[] {
110                CMD_SET , CMD_GET , CMD_NVLGET , CMD_REMOVE , CMD_SQL };
111
112        // 3.5.6.0 (2004/06/18) すべてを protected から private に変更します。
113        private String                  command         = CMD_SET;
114        private String                  key                     = null;
115        private String                  value           = null;
116//      private boolean                 isNullSet       = true;                 // NULL のときにセットし直すかどうか。
117        private transient DBTableModel  table           = null;
118        // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
119//      private String                  dbid            = "DEFAULT";
120        private String                  dbid            = null;
121        private String                  sql                     = null;
122        // 4.3.4.0 (2008/12/01) save属性追加
123        private boolean                 save            = false;
124
125        /**
126         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
127         *
128         * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
129         *
130         * @return      後続処理の指示
131         */
132        @Override
133        public int doStartTag() {
134                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
135//              if( CMD_SQL.equals( command ) ) {
136                if( useTag() && CMD_SQL.equals( command ) ) {
137                        return( EVAL_BODY_BUFFERED );           // Body を評価する
138                }
139                else {
140                        return( SKIP_BODY ); // Body を評価しない
141                }
142        }
143
144        /**
145         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
146         *
147         * @og.rev 3.1.1.0 (2003/03/28) ボディの内容を取得する処理を、CommonTagSupport で行う。
148         * @og.rev 3.6.0.8 (2004/11/19) エラー発生時に確実にリリースされるように try finally 追加
149         * @og.rev 3.8.6.3 (2006/11/30) SQL 文の前後のスペースを取り除きます。
150         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
151         * @og.rev 4.0.0.0 (2005/01/31) lang ⇒ ResourceManager へ変更
152         * @og.rev 5.1.9.0 (2010/08/01) TransactionTag 対応。上位に TransactionTag があれば、そこからConnection をもらう。
153         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更
154         * @og.rev 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
155         *
156         * @return      後続処理の指示(SKIP_BODY)
157         */
158        @Override
159        public int doAfterBody() {
160                sql = getBodyString().trim();
161
162                Query query = QueryFactory.newInstance();               // 4.0.0 (2005/01/31)
163                Transaction tran = null;
164                try {
165                        // 5.1.9.0 (2010/08/01) TransactionTag 対応
166//                      final Transaction tran ;
167                        TransactionTag tranTag = (TransactionTag)findAncestorWithClass( this,TransactionTag.class );
168                        if( tranTag == null ) {
169//                              tran = new TransactionReal( dbid,getApplicationInfo() );
170                                tran = new TransactionReal( getApplicationInfo() );             // 5.3.7.0 (2011/07/01) 引数変更
171                        }
172                        else {
173                                tran = tranTag.getTransaction();
174                        }
175                        query.setTransaction( dbid,tran );      // 5.1.9.0 (2010/08/01) TransactionTag 対応
176
177//                      query.setConnectionID( dbid );
178                        query.setResourceManager( getResource() );      // 4.0.0 (2005/01/31)
179
180                        query.setStatement( sql );
181//                      query.setApplicationInfo( getApplicationInfo() );       // 3.8.7.0 (2006/12/15)
182                        query.execute();
183
184                        table = query.getDBTableModel();
185                }
186                finally {
187//                      if( query != null ) { query.close(); }
188                        QueryFactory.close( query );
189                        if( tran != null ) { tran.close(); }            // 5.3.8.0 (2011/08/01) Transaction発生箇所でclose()
190                }
191                return(SKIP_BODY);
192        }
193
194        /**
195         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
196         *
197         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
198         * @og.rev 3.5.5.3 (2004/04/09) 値が null の場合は、""(ゼロ文字列)を返すフラグを採用
199         * @og.rev 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
200         *
201         * @return      後続処理の指示
202         */
203        @Override
204        public int doEndTag() {
205                debugPrint();           // 4.0.0 (2005/02/28)
206                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
207//              if( check( command, COMMAND_LIST ) ) {
208                if( useTag() && check( command, COMMAND_LIST ) ) {
209                        commandExec( command );
210
211                        if( CMD_GET.equals( command ) ) {
212                                jspPrint( value );
213                        }
214                        else if( CMD_NVLGET.equals( command ) ) {       // 3.5.5.3 (2004/04/09)
215                                jspPrint( nval(value,"") );
216                        }
217                }
218
219                return(EVAL_PAGE);
220        }
221
222        /**
223         * タグリブオブジェクトをリリースします。
224         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
225         *
226         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
227         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
228         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
229         * @og.rev 4.3.4.0 (2008/12/01) save属性対応
230         *
231         */
232        @Override
233        protected void release2() {
234                super.release2();
235                command         = CMD_SET;
236                key                     = null;
237                value           = null;
238//              isNullSet       = true;                 // NULL のときにセットし直すかどうか。
239                table           = null;
240//              dbid            = "DEFAULT";
241                dbid            = null;
242                sql                     = null;
243                save            = false;
244        }
245
246        /**
247         * コマンドを実行します。
248         *
249         * コマンドは,HTMLから(get/post)指定されますので,setCommand()メソッドで
250         * 登録します。
251         * コマンドを登録すると同時に,実行も行ないます。
252         *
253         * @og.rev 3.5.5.3 (2004/04/09) 値が null の場合は、""(ゼロ文字列)を返すフラグを採用
254         *
255         * @param   command コマンド(public static final 宣言されている文字列)
256         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.UserInfoTag.CMD_GET">コマンド定数</a>
257         */
258        protected void commandExec( final String command ) {
259                if( CMD_SQL.equals( command ) ) { setSQLAttribute() ; }
260                else if( CMD_SET.equals(    command ) ) { setAttribute() ;    }
261                else if( CMD_GET.equals(    command ) ) { getAttribute() ;    }
262                else if( CMD_NVLGET.equals( command ) ) { getAttribute() ;    } // 3.5.5.3 (2004/04/09)
263                else if( CMD_REMOVE.equals( command ) ) { removeAttribute() ; }
264        }
265
266        /**
267         * UserInfoの文字列を登録します。
268         *
269         * @og.rev 4.3.4.0 (2008/12/01) GE20(ユーザー定数)へ登録するかのフラグを追加
270         *
271         */
272        private void setAttribute() {
273//              if( isNullSet ) {
274//                      setUserInfo( key, value );
275                        setUserInfo( key, value, save );
276//              }
277        }
278
279        /**
280         * UserInfoの文字列を作成します。
281         *
282         */
283        private void getAttribute() {
284                value = getUserInfo( key );
285        }
286
287        /**
288         * UserInfoの文字列を削除します。
289         *
290         * @og.rev 5.3.6.0 (2011/06/01) GE20(ユーザー定数)から削除するかのフラグを追加
291         */
292        private void removeAttribute() {
293                UserInfo userInfo = getUser();
294//              userInfo.removeAttribute( key );
295                userInfo.removeAttribute( key, save );
296        }
297
298        /**
299         * UserInfoの文字列を指定のSQL文より作成します。
300         *
301         * @og.rev 4.3.4.0 (2008/12/01) GE20(ユーザー定数)へ登録するかのフラグを追加
302         *
303         */
304        private void setSQLAttribute() {
305                if( table == null || table.getRowCount() == 0 ) { return ; }
306
307                int row    = 0;
308                int clmCnt = table.getColumnCount();
309                for( int clm=0; clm<clmCnt; clm++ ) {
310                        String clmkey = table.getColumnName( clm );
311                        String clmval = table.getValue( row,clm );
312//                      setUserInfo( clmkey,clmval );
313                        setUserInfo( clmkey, clmval, save );
314                }
315        }
316
317        /**
318         * 【TAG】コマンド(SET,GET,NVLGET,REMOVE,SQL)をセットします(初期値:SET)。
319         *
320         * @og.tag
321         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
322         * フィールド定数値のいずれかを、指定できます。
323         * 何も設定されない、または、null の場合は、"SET" が初期値にセットされます。
324         * SQL の場合、検索結果の戻り値が複数存在する場合は、最初の1件目のみ使用します。
325         *
326         * @param       cmd コマンド(public static final 宣言されている文字列)
327         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.UserInfoTag.CMD_SET">コマンド定数</a>
328         */
329        public void setCommand( final String cmd ) {
330                String cmd2 = getRequestParameter( cmd );
331                if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
332        }
333
334        /**
335         * 【TAG】UserInfo に登録するキーをセットします(予約語:JNAME,ID,PASSWD,IDNO,INFO,LANG,ROLE,IPADDRESS,LOGINTIME)。
336         *
337         * @og.tag UserInfo に登録するキーをセットします。
338         *
339         * @param       inkey UserInfo に登録するキー
340         */
341        public void setKey( final String inkey ) {
342                key = getRequestParameter( inkey ).toUpperCase(Locale.JAPAN);
343                if( key.startsWith( "USER." ) ) {
344                        key = key.substring( 5 );
345                }
346        }
347
348        /**
349         * 【TAG】UserInfo に登録する値をセットします。
350         *
351         * @og.tag UserInfo に登録する値をセットします。
352         *
353         * @param       val     UserInfoに登録する値
354         */
355        public void setValue( final String val ) {
356                value = getRequestParameter( val );
357        }
358
359        /**
360         * 【TAG】UserInfo に登録した値を永続化するかを指定します。
361         *
362         * @og.tag
363         * UserInfo に登録した値を永続化するかを指定します。
364         * trueが指定された場合、UserInfoに設定された値は、GE20(ユーザー定数)に保存され、
365         * UserInfoが再作成されるタイミングで自動的に復元されます。
366         * ここで、登録された値は、そのユーザーの全てのロールに対して有効となります。
367         * 初期値は、false(永続化しない)です。
368         *
369         * @param       sv      登録値を永続化するか
370         */
371        public void setSave( final String sv ) {
372                save = nval( getRequestParameter( sv ),save );
373        }
374
375//      /**
376//       * 【廃止】Query を実行して、value に値をセットするかどうかを指定します。
377//       *
378//       * @og.tag
379//       * 初期値は、実行しない ("false")
380//       *
381//       * @og.rev 3.1.0.1 (2003/03/26) query 属性を非推奨属性とします。内部では使用しません。
382//       *
383//       * @param   flag Query を実行する ("true")/実行しない(それ以外)
384//       * @deprecated
385//       */
386//      @Deprecated public void setQuery( final String flag ) {
387//              // ここでは処理を行いません。
388//      }
389
390//      /**
391//       * 【廃止】value が NULL の時に、設定するかどうか[true/false]を指定します(初期値:true)。
392//       *
393//       * @og.tag
394//       * true の場合は, null のときでもセットします。
395//       * false の場合は, null のときは、既存の値を置き換えません。
396//       * 初期値は、null のときでもセットするです。 ("true")
397//       *
398//       * @param   flag NULL の時に、設定する ("true")/設定しない(それ以外)
399//       * @deprecated
400//       */
401//      @Deprecated public void setNullSet( final String flag ) {
402//              isNullSet = nval( getRequestParameter( flag ),isNullSet );
403//      }
404
405        /**
406         * 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。
407         *
408         * @og.tag Queryオブジェクトを作成する時のDB接続IDを指定します。
409         *
410         * @param       id データベース接続ID
411         */
412        public void setDbid( final String id ) {
413                dbid = nval( getRequestParameter( id ),dbid );
414        }
415
416        /**
417         * シリアライズ用のカスタムシリアライズ書き込みメソッド
418         *
419         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
420         * @serialData 一部のオブジェクトは、シリアライズされません。
421         *
422         * @param       strm    ObjectOutputStreamオブジェクト
423         * @throws IOException  入出力エラーが発生した場合
424         */
425        private void writeObject( final ObjectOutputStream strm ) throws IOException {
426                strm.defaultWriteObject();
427        }
428
429        /**
430         * シリアライズ用のカスタムシリアライズ読み込みメソッド
431         *
432         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
433         *
434         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
435         * @serialData 一部のオブジェクトは、シリアライズされません。
436         *
437         * @param       strm    ObjectInputStreamオブジェクト
438         * @see #release2()
439         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
440         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
441         */
442        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
443                strm.defaultReadObject();
444        }
445
446        /**
447         * このオブジェクトの文字列表現を返します。
448         * 基本的にデバッグ目的に使用します。
449         *
450         * @return このクラスの文字列表現
451         */
452        @Override
453        public String toString() {
454                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
455                                .println( "VERSION"                     ,VERSION        )
456                                .println( "command"                     ,command        )
457                                .println( "key"                         ,key            )
458                                .println( "value"                       ,value          )
459//                              .println( "isNullSet"           ,isNullSet      )
460                                .println( "dbid"                        ,dbid           )
461                                .println( "sql"                         ,sql            )
462                                .println( "save"                        ,save           )
463                                .println( "COMMAND_LIST"        ,COMMAND_LIST   )
464                                .println( "Other..."    ,getAttributes().getAttribute() )
465                                .fixForm().toString() ;
466        }
467}