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     */
016    package org.opengion.hayabusa.taglib;
017    
018    import org.opengion.hayabusa.common.HybsSystem;
019    import org.opengion.hayabusa.common.HybsSystemException;
020    import org.opengion.fukurou.util.StringUtil;
021    import static org.opengion.fukurou.util.StringUtil.nval ;
022    
023    import org.apache.commons.codec.binary.Base64 ;
024    import java.nio.charset.Charset;                // 5.5.2.6 (2012/05/25)
025    
026    /**
027     * Cookie を読み書きするタグですã?
028     *
029     * Cookie は少量のæƒ??ã‚?Servlet から Web ブラウザに送りã€?ブラウザにそれã‚?
030     * 維持しもらã�??以降ã?アクセスでサーバに送り返してもらã�?»•çµ?�§すã?
031     * Cookie の値はクライアントをä¸?„�に識別できるようになってã�?‚‹のでä¸?ˆ¬に
032     * セãƒ?‚·ョン管ç�?�«用ã�?‚‰れてã�?�¾すã?
033     *
034     * Cookie には名前と値がä¸?�¤ありますが、他にコメントやパス、ドメインã€?
035     * æœ?•·存続期間ã?バã?ジョンとã�?�£たオプショナルな属æ?もありますã?
036     * Web ブラウザの中にはオプショナルな属æ?の扱ã�?�«バグがあるものがありますã?
037     * こã?ため、Servlet の相互運用性を高めるためにはあまり使わなã�?�»ã�?�Œã�?�„でしょã�??
038     *
039     * 標準ã? JavaScript で登録機è?はサポã?トしてã�?�¾したがã?メモリのみで、かつ
040     * 画面単位ã?書き込みのみでしたã€?
041     * 今回の cookie タグでは、永続化(maxAge)の設定や、シスãƒ?ƒ å†?CONTEXT_NAME以ä¸?
042     * での共æœ?ãƒ?ƒ•ォルãƒ?ã‚??そã?変更、ドメインを指定しての共æœ?domain)などの
043     * 機è?を持ってã�?�¾すã?
044     * またã?漢字コードでの読み書ã�?useBase64)にも対応してã�?�¾すã?
045     * 読み込みに関しては、漢字をæŒ?®šしなければ、{@SYS.COOKIE.カラãƒ?��}で、使用可能ですã?
046     * è¤?•°の読み込み、またã?漢字コードを含ã‚?‚¯ãƒ?‚­ーの場合ã?、読み込み(action="LOAD")
047     * してください。指定ã?キー以外に、別名に読み込ã‚?aliasNames)事も可能ですã?
048     *
049     * @og.formSample
050     * ●形式ï¼?
051     *    <og:cookie
052     *        action    = "SAVE"       Cookie に対するアクションを指定しますã?(SAVE|LOAD|DELETE)
053     *        keys      = "AAA,BBB"    キーをCSV形式でè¤?•°æŒ?®šできますã?
054     *        vals      = "VAL1,VAL2"  値をCSV形式でè¤?•°æŒ?®šできますã?
055     *        path      = "/ge"        クライアントがこã? Cookie を返さなくてはã�?�‘なã�?ƒ‘スを指定しますã?
056     *        domain    = ".foo.com"   こã? Cookie がどこで生æ?されたかを表すドメインを指定しますã?
057     *        maxAge    = "3600"       Cookie のæœ?•·存続期間を秒単位で設定しますã?
058     *        useBase64 = "false"      漢字等ã??’Byteæ–?­—を使用する場合に、BASE64で処ç�?�—ますã?[true/false]
059     *    >
060     * ●body?šなã�?
061     *
062     * ●Tag定義??
063     *   <og:cookie
064     *       action           ○ã?TAG】アクション(SAVE,LOAD,DELETE)をセãƒ?ƒˆしまã�?å¿??)ã€?
065     *       keys             ○ã?TAG】クãƒ?‚­ーのキーをCSV形式でè¤?•°æŒ?®šしまã�?å¿??)ã€?
066     *       vals               【TAG】keys属æ?に対応するå?をCSV形式でè¤?•°æŒ?®šしまã�?
067     *       aliasNames         【TAG】クãƒ?‚­ーのキーの別名をCSV形式でè¤?•°æŒ?®šしまã�?
068     *       path               【TAG】クライアントがこã? Cookie を返さなくてはã�?�‘なã�?ƒ‘スを指定しまã�?初期値:/+CONTEXT_NAME)
069     *       domain             【TAG】この Cookie がどこで生æ?されたかを表すドメインを指定しまã�?初期値:付与したサーãƒ?
070     *       maxAge             【TAG】Cookie のæœ?•·存続期間を秒単位で設定しまã�?初期値: -1 )
071     *       useBase64          【TAG】漢字等ã?æ–?­—を扱ã�??合に、BASE64で処ç�?‚’行うかどã�?�‹[true/false]を設定しまã�?初期値:false )
072     *       debug              【TAG】デバッグæƒ??をå?力するかどã�?�‹[true/false]を指定しまã�?初期値:false)
073     *   />
074     *
075     * ●使用ä¾?
076     *    例ï¼?設å®?è¤?•°キーを同時に書き込ã‚?�“とが可能ですã?
077     *        <og:cookie
078     *            action="SAVE" keys="CDJ,FG_NAME" vals="{@CDJ},{@NAME}"
079     *        />
080     *
081     *    例ï¼?取å¾?cookieタグで取得すると、それ以降では {@CDJ} ã‚?{@NAME} で扱えますã?
082     *          aliasNames 属æ?を使わなã�??合ã?、keys にæŒ?®šした変数にセãƒ?ƒˆされますã?
083     *        <og:cookie
084     *            action="LOAD" keys="CDJ,FG_NAME" aliasNames="CDJ,NAME"
085     *        />
086     *
087     *    例ï¼?取å¾?SYS パラメータでの取得も可能ですã?
088     *        {@SYS.COOKIE.CDJ}
089     *
090     *    例ï¼? QUERY画面では値の表示(LOAD)を行い、RESULT画面で値の設å®?SAVE)を行うケース
091     *
092     *        QUERY画面
093     *        <og:cookie action="LOAD" useBase64="true"
094     *                        keys="CLM,NAME" aliasNames="CLM,LABEL_NAME" />
095     *
096     *        <og:column name="CLM"        defaultVal="{@CLM}" />
097     *        <og:column name="LABEL_NAME" defaultVal="{@LABEL_NAME}"/>
098     *
099     *        RESULT画面
100     *        <og:cookie action="SAVE" maxAge="360000" useBase64="true"
101     *                        keys="CLM,NAME" vals="{@CLM},{@LABEL_NAME}" />
102     *
103     *    例ï¼? QUERY画面では、{@SYS.COOKIE.カラãƒ?��} で取得ã?
104     *        RESULT画面では、ムラタå†??シスãƒ?ƒ 共通に使える値をセãƒ?ƒˆã€?
105     *
106     *        QUERY画面
107     *        <og:column name="SYSTEM_ID" defaultVal="{@SYS.COOKIE.SYSTEM_ID}" />
108     *
109     *        RESULT画面
110     *        <og:cookie action="SAVE" maxAge="360000" domain=".opengion.org"
111     *                        keys="SYSTEM_ID" vals="{@SYSTEM_ID}" />
112     *
113     * @og.rev 3.8.0.2 (2005/06/30) 新規作æ?
114     * @og.group 画面制御
115     *
116     * @version  0.9.0  2000/10/17
117     * @author   Kazuhiko Hasegawa
118     * @since    JDK5.0,
119     */
120    public class CookieTag extends CommonTagSupport {
121            //* こã?プログラãƒ??VERSIONæ–?­—å?を設定しますã?       {@value} */
122            private static final String VERSION = "5.5.2.6 (2012/05/25)" ;
123    
124            private static final long serialVersionUID = 552620120525L ;
125    
126            /**
127             * プラãƒ?ƒˆフォーãƒ?¾�存ã?ãƒ?ƒ•ォルトã? Charset ですã?
128             * プラãƒ?ƒˆフォーãƒ?¾�存æ?をè?慮する場合ã?エンコード指定で作æ?しておく事をお勧めしますã?
129             *
130             * @og.rev 5.5.2.6 (2012/05/25) findbugs対å¿?
131             */
132            private static final Charset DEFAULT_CHARSET = Charset.defaultCharset() ;
133    
134            /** action 引数に渡す事ã?出来ã‚?アクション  設å®?{@value} */
135            public static final String ACT_SAVE = "SAVE" ;
136            /** action 引数に渡す事ã?出来ã‚?アクション  取å¾?{@value} */
137            public static final String ACT_LOAD = "LOAD" ;
138            /** action 引数に渡す事ã?出来ã‚?アクション  削除 {@value} */
139            public static final String ACT_DELETE = "DELETE" ;
140    
141            /** action 引数に渡す事ã?出来ã‚?アクション リスãƒ? */
142            private static final String[] ACTION_LIST = new String[] { ACT_SAVE , ACT_LOAD , ACT_DELETE };
143    
144            private String   action         = null;
145            private String[] keys           = null;
146            private String[] vals           = null;
147            private String[] aliasNames     = null;
148            private String   path           = "/" + HybsSystem.sys( "CONTEXT_NAME" );
149            private String   domain         = null;
150            private int      maxAge         = -1;
151            private boolean  useBase64      = false;
152    
153            /**
154             * Taglibの終äº?‚¿グが見つかったときに処ç�?�™ã‚?doEndTag() ã‚?オーバã?ライドしますã?
155             *
156             * @return      後続å?ç�??æŒ?¤º(EVAL_PAGE)
157             */
158            @Override
159            public int doEndTag() {
160                    debugPrint();           // 4.0.0 (2005/02/28)
161                    actionExec( action );
162    
163                    return(EVAL_PAGE);
164            }
165    
166            /**
167             * タグリブオブジェクトをリリースしますã?
168             * キャãƒ?‚·ュされて再利用されるã?で、フィールドã?初期設定を行いますã?
169             *
170             */
171            @Override
172            protected void release2() {
173                    super.release2();
174                    action          = null;
175                    keys            = null;
176                    vals            = null;
177                    aliasNames      = null;
178                    path            = "/" + HybsSystem.sys( "CONTEXT_NAME" );
179                    domain          = null;
180                    maxAge          = -1;
181                    useBase64       = false;
182            }
183    
184            /**
185             * アクションを実行しますã?
186             *
187             * アクションは action 属æ?でæŒ?®šしますã?
188             *
189             * @param       action  アクション(public static final 宣è¨?�•れてã�?‚‹æ–?­—å?)
190             */
191            private void actionExec( final String action ) {
192    
193                    if( ACT_SAVE.equals( action ) ) {
194                            saveCookies( maxAge );
195                    }
196                    else if( ACT_LOAD.equals( action ) ) {
197                            loadCookies();
198                    }
199                    else if( ACT_DELETE.equals( action ) ) {
200                            saveCookies( 0 );       // maxAge にゼロをセãƒ?ƒˆすると削除されますã?
201                    }
202                    else {
203                            String errMsg = "æŒ?®šã?アクションは実行できません。アクションエラー"
204                                                            + HybsSystem.CR
205                                                            + "action=[" + action + "] "
206                                                            + HybsSystem.CR
207                                                            + StringUtil.array2csv( ACTION_LIST ) ;
208                            throw new HybsSystemException( errMsg );
209                    }
210            }
211    
212            /**
213             * SAVE アクションを実行しますã?
214             *
215             * クãƒ?‚­ーに書き込みを行いますã?
216             *
217             * @param       maxAge  æœ?•·存続期é–? 0 なら削除 )
218             */
219            private void saveCookies( final int maxAge ) {
220            //      BASE64Encoder encoder = null;
221                    for( int i=0; i<keys.length; i++ ) {
222                            String value = nval (vals[i],"" );
223                            if( useBase64 && value.length() > 0 ) {
224            //                      if( encoder == null ) { encoder = new BASE64Encoder(); }
225            //                      value = encoder.encode( value.getBytes() ) ;
226    
227    //                              byte[] encoded = Base64.encodeBase64( value.getBytes() );
228    //                              value = new String( encoded );
229                                    byte[] encoded = Base64.encodeBase64( value.getBytes( DEFAULT_CHARSET ) );              // 5.5.2.6 (2012/05/25) findbugs対å¿?
230                                    value = new String( encoded,DEFAULT_CHARSET );                                                                  // 5.5.2.6 (2012/05/25) findbugs対å¿?
231                            }
232                            setCookie( keys[i], value, maxAge );
233                    }
234            }
235    
236            /**
237             * LOAD アクションを実行しますã?
238             *
239             * クãƒ?‚­ーから読み込みを行いますã?
240             *
241             */
242            private void loadCookies() {
243            //      BASE64Decoder decoder = null;
244                    if( aliasNames == null ) { aliasNames = keys; }
245    
246            //      try {
247                            for( int i=0; i<keys.length; i++ ) {
248                                    String value = getCookie( keys[i] );
249                                    if( useBase64 && value != null && value.length() > 0 ) {
250            //                              if( decoder == null ) { decoder = new BASE64Decoder(); }
251            //                              byte[] decoded = decoder.decodeBuffer( value );
252    //                                      byte[] decoded = Base64.decodeBase64( value.getBytes() );
253    //                                      value = new String( decoded );
254                                            byte[] decoded = Base64.decodeBase64( value.getBytes( DEFAULT_CHARSET ) );              // 5.5.2.6 (2012/05/25) findbugs対å¿?
255                                            value = new String( decoded,DEFAULT_CHARSET );                                                                  // 5.5.2.6 (2012/05/25) findbugs対å¿?
256                                    }
257                                    if( value != null ) {
258                                            setRequestAttribute( aliasNames[i],value );
259                                    }
260                            }
261            //      }
262            //      catch( IOException ex ) {
263            //              String errMsg = "BASE64Decoder エラー " + ex.toString();
264            //              throw new HybsSystemException( errMsg );
265            //      }
266            }
267    
268            /**
269             * 【TAG】アクション(SAVE,LOAD,DELETE)をセãƒ?ƒˆしますã?
270             *
271             * @og.tag
272             * アクションは,HTMLから(get/post)æŒ?®šされますã?で,ACT_xxx で設定される
273             * フィールド定数値のã�?�¥れかをã?æŒ?®šできますã?
274             * 無æŒ?®šã?場合ã?、なにもしませんã€?
275             *
276             * <table border="1" frame="box" rules="all" >
277             *   <caption>アクションの説æ˜?/caption>
278             *   <tr><th>action </th><th>名称</th><th>機è?</th></tr>
279             *   <tr><td>SAVE   </td><td>登録</td><td>æŒ?®šã? keys のキーに vals の値をセãƒ?ƒˆしますã?</td></tr>
280             *   <tr><td>LOAD   </td><td>取å¾?/td><td>æŒ?®šã? keys のクãƒ?‚­ーã‚?リクエスト中に)取得しますã?</td></tr>
281             *   <tr><td>DELETE </td><td>削除</td><td>æŒ?®šã? keys のクãƒ?‚­ーを削除しますã?</td></tr>
282             * </table>
283             *
284             * @param       act アクション(public static final 宣è¨?�•れてã�?‚‹æ–?­—å?)
285             * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.CookieTag.ACT_DELETE">アクション定数</a>
286             */
287            public void setAction( final String act ) {
288                    action = nval( getRequestParameter( act ),action );
289    
290                    if( action != null && !check( action, ACTION_LIST ) ) {
291                            String errMsg = "æŒ?®šã?アクションは実行できません。アクションエラー"
292                                                            + HybsSystem.CR
293                                                            + "action=[" + action + "] "
294                                                            + HybsSystem.CR
295                                                            + StringUtil.array2csv( ACTION_LIST ) ;
296                            throw new HybsSystemException( errMsg );
297                    }
298            }
299    
300            /**
301             * 【TAG】クãƒ?‚­ーのキーをCSV形式でè¤?•°æŒ?®šしますã?
302             *
303             * @og.tag
304             * クãƒ?‚­ーにセãƒ?ƒˆするときã?キーを指定しますã?カンマ区åˆ?‚Šでè¤?•°æŒ?®šできますã?
305             * vals 属æ?には、キーに対応するå?をã?設定してくださいã€?
306             * åˆ?§£方法ã?、CSV変数をå?にåˆ?§£してから、getRequestParameter で値を取得しますã?
307             * こうしなã�?�¨ãƒ??タ自身にカンマを持ってã�?‚‹場合にåˆ?§£をミスる為ですã?
308             *
309             * @param       key     クãƒ?‚­ーのキー
310             */
311            public void setKeys( final String key ) {
312                    keys = getCSVParameter( key );
313            }
314    
315            /**
316             * 【TAG】クãƒ?‚­ーのキーの別名をCSV形式でè¤?•°æŒ?®šしますã?
317             *
318             * @og.tag
319             * クãƒ?‚­ーから値を取得すã‚?action="LOAD")場合に、読み込みキー(keys)に対応すã‚?
320             * 別名をæŒ?®šすることで、別名ã?変数に読み込んだ値を登録することがå?来ますã?
321             * 別名をæŒ?®šしなã�??合ã?、keys にæŒ?®šされた名前がã?使用されますã?
322             * åˆ?§£方法ã?、CSV変数をå?にåˆ?§£してから、getRequestParameter で値を取得しますã?
323             * こうしなã�?�¨ãƒ??タ自身にカンマを持ってã�?‚‹場合にåˆ?§£をミスる為ですã?
324             *
325             * @param       names   クãƒ?‚­ーの別å�?
326             */
327            public void setAliasNames( final String names ) {
328                    aliasNames = getCSVParameter( names );
329            }
330    
331            /**
332             * 【TAG】keys属æ?に対応するå?をCSV形式でè¤?•°æŒ?®šしますã?
333             *
334             * @og.tag
335             * キーに設定したå?をã?カンマ区åˆ?‚Šæ–?­—でè¤?•°して出来ますã?
336             * æŒ?®šé?序ã?、キーと同じにしておいて下さã�??
337             * åˆ?§£方法ã?、CSV変数をå?にåˆ?§£してから、getRequestParameter で値を取得しますã?
338             * こうしなã�?�¨ãƒ??タ自身にカンマを持ってã�?‚‹場合にåˆ?§£をミスる為ですã?
339             *
340             * @param       val     keys属æ?に対応するå?
341             */
342            public void setVals( final String val ) {
343                    vals = getCSVParameter( val );
344            }
345    
346            /**
347             * 【TAG】クライアントがこã? Cookie を返さなくてはã�?�‘なã�?ƒ‘スを指定しまã�?初期値:/+CONTEXT_NAME)ã€?
348             *
349             * @og.tag
350             * こã?値を指定すると Cookie が該当するディレクトリå†??さらにã€?
351             * サブディレクトリに存在する全てのペã?ジから参ç?できるようになりますã?
352             * Cookie のパスには Cookie をセãƒ?ƒˆした Servlet が含まれてã�?�ªければなりませんã€?
353             * 例えばã€?catalog を指定したとしますã?こã?ときã? サーバã? /catalog 以下ã?全ての
354             * ãƒ?‚£レクトリから Cookie が見えるよã�?�«なりますã?
355             * 初期値はã€?/" + CONTEXT_NAME ですã?
356             *
357             * Cookie のパス名指定につã�?�¦の詳細は RFC2109 を参照してくださいã€?
358             *
359             * @param       uri パスを指定するString
360             */
361            public void setPath( final String uri ) {
362                    path = nval( getRequestParameter( uri ),path );
363            }
364    
365            /**
366             * 【TAG】この Cookie がどこで生æ?されたかを表すドメインを指定しまã�?初期値:付与したサーãƒ?ã€?
367             *
368             * @og.tag
369             * ドメイン名ã?形式ã? RFC2109 でæŒ?®šされてã�?�¾すã?
370             * ドメイン名ã? (.foo.com のように) ドットで始まりますã? こã?ように設定するとã€?
371             * Cookie はæŒ?®šされた Domain Name System (DNS) のゾーンå†??サーバから見えã‚?
372             * ようになりまã�?例えば、www.foo.com) からは見えるけれど、a.b.foo.com からは
373             * 見えなã�?�¨ã�?�†ようにでã�?ã€?ãƒ?ƒ•ォルトでは Cookie を付与したサーバにしか送り返しませんã€?
374             *
375             * @param       pattern こã? Cookie が見えてもよã�?ƒ‰メイン名をæŒ?®šするString
376             */
377            public void setDomain( final String pattern ) {
378                    domain = nval( getRequestParameter( pattern ),domain );
379            }
380    
381            /**
382             * 【TAG】Cookie のæœ?•·存続期間を秒単位で設定しまã�?初期値: -1 )ã€?
383             *
384             * @og.tag
385             * 正の値が指定されると Cookie はある秒数が過ぎた後ã?削除されますã?
386             * こã?値は、Cookie の有効期限がå?れる æœ?•· 存続期間であることに注意してくださいã€?
387             * Cookie の現在までの存続期間ではありませんã€?
388             *
389             * è²??値は Cookie が永続的に保存されなã�?�“とを意味してã�?�¾すã? こã?場合ã?
390             * Web ブラウザが終äº?�™ると Cookie も削除されますã? 0 とã�?�†値を指定すると
391             * Cookie が削除されることになりますã?
392             * 初期値はã€?1(永続的に保存されなã�?ですã?
393             *
394             * @param       expiry Cookie のæœ?•·存続期間を秒単位でæŒ?®šする整数値ã€?è²??値は Cookie を保存しなã�?? 0 なã‚?Cookie を削除する意味となるã?
395             */
396            public void setMaxAge( final String expiry ) {
397                    maxAge = nval( getRequestParameter( expiry ),maxAge );
398            }
399    
400            /**
401             * 【TAG】漢字等ã?æ–?­—を扱ã�??合に、BASE64で処ç�?‚’行うかどã�?�‹[true/false]を設定しまã�?初期値:false )ã€?
402             *
403             * @og.tag
404             * クãƒ?‚­ーへの読み書きã?、ASCII に限られますã?漢字等ã?コードを書き込ã‚??合ã?ã€?
405             * BASE64でエンコードして書き込ã‚?¿?¦�がありますã?読み込ã‚??合も同様ですã?
406             * ただしã?ä¸?ˆ¬のASCIIは、BASE64 ではエンコードしなã�?�Ÿめã?外部でæŒ?®šするå¿?¦�がありますã?
407             * BASE64 で書き込んだ場合ã?、{&#064;SYS.COOKIE.CDJ} での取得ã?できませんのでã€?
408             * action="LOAD" で、取得してくださいã€?
409             * 初期値は、false(使用しなã�?ですã?
410             *
411             * @param       flag 漢字等ã?æ–?­—を扱ã�??合に、BASE64で処ç�?‚’行うかどã�?�‹[true/false]
412             */
413            public void setUseBase64( final String flag ) {
414                    useBase64 = nval( getRequestParameter( flag ),useBase64 );
415            }
416    
417            /**
418             * こã?オブジェクトã?æ–?­—å?表現を返しますã?
419             * 基本çš?�«ãƒ?ƒ�ãƒ?‚°目çš?�«使用しますã?
420             *
421             * @return こã?クラスのæ–?­—å?表現
422             */
423            @Override
424            public String toString() {
425                    return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
426                                    .println( "VERSION"             ,VERSION        )
427                                    .println( "action"              ,action         )
428                                    .println( "keys"                ,keys           )
429                                    .println( "vals"                ,vals           )
430                                    .println( "aliasNames"  ,aliasNames     )
431                                    .println( "path"                ,path           )
432                                    .println( "domain"              ,domain         )
433                                    .println( "maxAge"              ,maxAge         )
434                                    .println( "useBase64"   ,useBase64      )
435                                    .println( "Other..."    ,getAttributes().getAttribute() )
436                                    .fixForm().toString() ;
437            }
438    }