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             * <th><td>action   </td><td>名称</td><td>機?</td></th>
278             * <tr><td>SAVE             </td><td>登録</td><td>?? keys のキーに vals の値をセ?します?</td></tr>
279             * <tr><td>LOAD             </td><td>取?/td><td>?? keys のク?ー?リクエスト中に)取得します?</td></tr>
280             * <tr><td>DELETE   </td><td>削除</td><td>?? keys のク?ーを削除します?</td></tr>
281             * </table>
282             *
283             * @param       act アクション(public static final 宣?れて???)
284             * @see         <a href="{&#064;docRoot}/constant-values.html#org.opengion.hayabusa.taglib.CookieTag.ACT_DELETE">アクション定数</a>
285             */
286            public void setAction( final String act ) {
287                    action = nval( getRequestParameter( act ),action );
288    
289                    if( action != null && !check( action, ACTION_LIST ) ) {
290                            String errMsg = "??アクションは実行できません。アクションエラー"
291                                                            + HybsSystem.CR
292                                                            + "action=[" + action + "] "
293                                                            + HybsSystem.CR
294                                                            + StringUtil.array2csv( ACTION_LIST ) ;
295                            throw new HybsSystemException( errMsg );
296                    }
297            }
298    
299            /**
300             * 【TAG】ク?ーのキーをCSV形式で??します?
301             *
302             * @og.tag
303             * ク?ーにセ?するとき?キーを指定します?カンマ区?で??できます?
304             * vals 属?には、キーに対応する?を?設定してください?
305             * ?方法?、CSV変数を?に?してから、getRequestParameter で値を取得します?
306             * こうしな???タ自身にカンマを持って?場合に?をミスる為です?
307             *
308             * @param       key     ク?ーのキー
309             */
310            public void setKeys( final String key ) {
311                    keys = getCSVParameter( key );
312            }
313    
314            /**
315             * 【TAG】ク?ーのキーの別名をCSV形式で??します?
316             *
317             * @og.tag
318             * ク?ーから値を取得す?action="LOAD")場合に、読み込みキー(keys)に対応す?
319             * 別名を?することで、別名?変数に読み込んだ値を登録することが?来ます?
320             * 別名を?しな??合?、keys に?された名前が?使用されます?
321             * ?方法?、CSV変数を?に?してから、getRequestParameter で値を取得します?
322             * こうしな???タ自身にカンマを持って?場合に?をミスる為です?
323             *
324             * @param       names   ク?ーの別?
325             */
326            public void setAliasNames( final String names ) {
327                    aliasNames = getCSVParameter( names );
328            }
329    
330            /**
331             * 【TAG】keys属?に対応する?をCSV形式で??します?
332             *
333             * @og.tag
334             * キーに設定した?を?カンマ区??で?して出来ます?
335             * ??序?、キーと同じにしておいて下さ??
336             * ?方法?、CSV変数を?に?してから、getRequestParameter で値を取得します?
337             * こうしな???タ自身にカンマを持って?場合に?をミスる為です?
338             *
339             * @param       val     keys属?に対応する?
340             */
341            public void setVals( final String val ) {
342                    vals = getCSVParameter( val );
343            }
344    
345            /**
346             * 【TAG】クライアントがこ? Cookie を返さなくては?な?スを指定しま?初期値:/+CONTEXT_NAME)?
347             *
348             * @og.tag
349             * こ?値を指定すると Cookie が該当するディレクトリ??さらに?
350             * サブディレクトリに存在する全てのペ?ジから参?できるようになります?
351             * Cookie のパスには Cookie をセ?した Servlet が含まれて?ければなりません?
352             * 例えば?catalog を指定したとします?こ?とき? サーバ? /catalog 以下?全ての
353             * ?レクトリから Cookie が見えるよ?なります?
354             * 初期値は?/" + CONTEXT_NAME です?
355             *
356             * Cookie のパス名指定につ?の詳細は RFC2109 を参照してください?
357             *
358             * @param       uri パスを指定するString
359             */
360            public void setPath( final String uri ) {
361                    path = nval( getRequestParameter( uri ),path );
362            }
363    
364            /**
365             * 【TAG】この Cookie がどこで生?されたかを表すドメインを指定しま?初期値:付与したサー??
366             *
367             * @og.tag
368             * ドメイン名?形式? RFC2109 で?されて?す?
369             * ドメイン名? (.foo.com のように) ドットで始まります? こ?ように設定すると?
370             * Cookie は?された Domain Name System (DNS) のゾーン??サーバから見え?
371             * ようになりま?例えば、www.foo.com) からは見えるけれど、a.b.foo.com からは
372             * 見えな??ようにで???ォルトでは Cookie を付与したサーバにしか送り返しません?
373             *
374             * @param       pattern こ? Cookie が見えてもよ?メイン名を?するString
375             */
376            public void setDomain( final String pattern ) {
377                    domain = nval( getRequestParameter( pattern ),domain );
378            }
379    
380            /**
381             * 【TAG】Cookie の?存続期間を秒単位で設定しま?初期値: -1 )?
382             *
383             * @og.tag
384             * 正の値が指定されると Cookie はある秒数が過ぎた後?削除されます?
385             * こ?値は、Cookie の有効期限が?れる ? 存続期間であることに注意してください?
386             * Cookie の現在までの存続期間ではありません?
387             *
388             * ??値は Cookie が永続的に保存されな?とを意味して?す? こ?場合?
389             * Web ブラウザが終?ると Cookie も削除されます? 0 と?値を指定すると
390             * Cookie が削除されることになります?
391             * 初期値は?1(永続的に保存されな?です?
392             *
393             * @param       expiry Cookie の?存続期間を秒単位で?する整数値???値は Cookie を保存しな?? 0 な?Cookie を削除する意味となる?
394             */
395            public void setMaxAge( final String expiry ) {
396                    maxAge = nval( getRequestParameter( expiry ),maxAge );
397            }
398    
399            /**
400             * 【TAG】漢字等??を扱??合に、BASE64で処?行うかど?[true/false]を設定しま?初期値:false )?
401             *
402             * @og.tag
403             * ク?ーへの読み書き?、ASCII に限られます?漢字等?コードを書き込??合??
404             * BASE64でエンコードして書き込??があります?読み込??合も同様です?
405             * ただし??のASCIIは、BASE64 ではエンコードしな?め?外部で?する?があります?
406             * BASE64 で書き込んだ場合?、{&#064;SYS.COOKIE.CDJ} での取得?できませんので?
407             * action="LOAD" で、取得してください?
408             * 初期値は、false(使用しな?です?
409             *
410             * @param       flag 漢字等??を扱??合に、BASE64で処?行うかど?[true/false]
411             */
412            public void setUseBase64( final String flag ) {
413                    useBase64 = nval( getRequestParameter( flag ),useBase64 );
414            }
415    
416            /**
417             * こ?オブジェクト???表現を返します?
418             * 基本???目?使用します?
419             *
420             * @return こ?クラスの??表現
421             */
422            @Override
423            public String toString() {
424                    return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
425                                    .println( "VERSION"             ,VERSION        )
426                                    .println( "action"              ,action         )
427                                    .println( "keys"                ,keys           )
428                                    .println( "vals"                ,vals           )
429                                    .println( "aliasNames"  ,aliasNames     )
430                                    .println( "path"                ,path           )
431                                    .println( "domain"              ,domain         )
432                                    .println( "maxAge"              ,maxAge         )
433                                    .println( "useBase64"   ,useBase64      )
434                                    .println( "Other..."    ,getAttributes().getAttribute() )
435                                    .fixForm().toString() ;
436            }
437    }