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.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
019
020import static org.opengion.fukurou.util.StringUtil.nval ;
021
022/**
023 * switch タグは、指定された条件を、case タグに伝えます。
024 *
025 * 各属性は、{@XXXX} 変数が使用できます。
026 * これは、ServletRequest から、XXXX をキーに値を取り出し、この変数に
027 * 割り当てます。つまり、このXXXXをキーにリクエストすれば、
028 * この変数に値をセットすることができます。
029 *
030 * @og.formSample
031 * ●形式:<og:switch key="・・・" >
032 *            <og:case match="A" > ・・・ </og:case>
033 *            <og:case match="B" > ・・・ </og:case>
034 *            <og:case match="C" > ・・・ </og:case>
035 *            <og:case isDefault="true" > ・・・ </og:case>
036 *         </og:switch>
037 * ●body:あり(EVAL_BODY_INCLUDE:BODYをインクルードし、{@XXXX} は解析しません)
038 *
039 * ●Tag定義:
040 *   <og:switch
041 *       key              ○【TAG】switch のマッチ判定用のキーを設定します(必須)。
042 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
043 *   >   ... Body ...
044 *   </og:switch>
045 *
046 * ●使用例
047 *         <og:switch key="{@PARAM}" >
048 *            <og:case match="A" > 処理A </og:case>
049 *            <og:case match="B" > 処理B </og:case>
050 *            <og:case match="C" > 処理C </og:case>
051 *            <og:case isDefault="true" > 処理X </og:case>
052 *         </og:switch>
053 *
054 *          ・switch の key に対して、case の match に指定された値が、マッチ(switch_key.match( case_match ))
055 *            した場合に、case の BODY 部分が処理されます。
056 *            マッチしなければ、BODY部は、スキップされます。
057 *          ・isDefault="true" の場合は、どれとも マッチしなかった場合に、実行されます。
058 *          ・Javaの switch-case 文は、最初に処理された case 以降を処理します。通常は、break を入れて
059 *            後続処理を実行されないようにしています。
060 *            この、switch-case タグは、caseタグの isBreak 属性で制御します。初期値が isBreak="true" に、
061 *            なっているため、通常は、どれかの case が実行された段階で、switchの処理は、終了されます。
062 *            isBreak="false" にすると、switchから抜けずに、継続して case との match を実行します。
063 *            この場合、Java等と異なるのは、直後のcase文が実行されるのではなく、あくまで match 作業が
064 *            継続されるということです。つまり、複数の case で処理を行いたい場合は、isBreak="false" に
065 *            すると同時に、match 条件もそれぞれで、マッチするように設定する必要があります。
066 *
067 *         <og:switch key="{@PARAM}" >
068 *            <og:case match="[1]"   isBreak="false" > 処理A </og:case>
069 *            <og:case match="[12]"  isBreak="false" > 処理B </og:case>
070 *            <og:case match="[123]" isBreak="false" > 処理C </og:case>
071 *            <og:case isNull="true" > 処理X </og:case>
072 *            <og:case isDefault="true" > 処理Y </og:case>
073 *         </og:switch>
074 *
075 *          ・上記指定では、isBreak="false" が指定されているため、マッチした後も継続して判定処理が実施されます。
076 *          ・上記例で言うと、PARAM が "1" の場合、上記3つともにマッチします。
077 *          ・isNull="true" は、switch の key が null の場合に成立します。(null とは、ゼロ文字列も含む)
078 *
079 * @og.group 画面制御
080 * @og.rev 5.2.3.0 (2010/12/01) 新規追加
081 *
082 * @version  5.2.3.0 (2010/12/01)
083 * @author       Kazuhiko Hasegawa
084 * @since    JDK1.6,
085 */
086public class SwitchTag extends CommonTagSupport {
087        /** このプログラムのVERSION文字列を設定します。   {@value} */
088        private static final String VERSION = "6.4.2.0 (2016/01/29)" ;
089        private static final long serialVersionUID = 642020160129L ;
090
091        private String  switchKey       ;
092        private boolean useMatch        = true;         // マッチ処理を継続して行う場合、true  (5.3.0.0 (2010/12/01) 変数名変更)
093
094        /**
095         * デフォルトコンストラクター
096         *
097         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
098         */
099        public SwitchTag() { super(); }         // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
100
101        /**
102         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
103         *
104         * @return      後続処理の指示( EVAL_BODY_INCLUDE )
105         */
106        @Override
107        public int doStartTag() {
108                useMatch        = true; // 初期化
109
110                return EVAL_BODY_INCLUDE ;      // Body インクルード( extends TagSupport 時)
111        }
112
113        /**
114         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
115         *
116         * @return      後続処理の指示
117         */
118        @Override
119        public int doEndTag() {
120                debugPrint();
121
122                return EVAL_PAGE ;
123        }
124
125        /**
126         * タグリブオブジェクトをリリースします。
127         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
128         *
129         */
130        @Override
131        protected void release2() {
132                super.release2();
133                switchKey       = null;
134                useMatch        = true;
135        }
136
137        /**
138         * 【TAG】switch のマッチ判定用のキーを設定します。
139         *
140         * @og.tag switch のマッチ判定用のキーを設定します。
141         *
142         * @param       key マッチ判定用のキー
143         * @see         #getKey()
144         */
145        public void setKey( final String key ) {
146                switchKey = nval( getRequestParameter( key ),switchKey );
147        }
148
149        /**
150         * switch のマッチ判定用のキーを取得します。
151         *
152         * case タグで、この値を取り出して、マッチ判定を行います。
153         *
154         * @return      マッチ判定用のキー
155         * @see         #setKey( String )
156         */
157        protected String getKey() {
158                return switchKey;
159        }
160
161        /**
162         * case タグが、ブレイクした場合に、このメソッドを呼び出します。
163         *
164         * これは、 case タグが isBreak="true" でマッチした場合、このメソッドを
165         * 呼び出し、isMatch フラグを false に設定します。
166         * 他の case は、このフラグを参照して、false であれば、スルーします。
167         *
168         * @see         #isMatch()
169         */
170        protected void setBreak() {
171                useMatch= false ;
172        }
173
174        /**
175         * すでにマッチしたかどうかを返します。
176         *
177         * これは、 case タグが 処理を継続するかどうかの判定に利用します。
178         * case タグが isBreak="true" でマッチした場合、isMatch フラグは、
179         * false が返りますので、継続処理しません。
180         *
181         * @return      マッチしたかどうか[true:継続判定/false:スルー]
182         * @see         #setBreak()
183         */
184        protected boolean isMatch() {
185                return useMatch ;
186        }
187
188        /**
189         * このオブジェクトの文字列表現を返します。
190         * 基本的にデバッグ目的に使用します。
191         *
192         * @return このクラスの文字列表現
193         * @og.rtnNotNull
194         */
195        @Override
196        public String toString() {
197                return ToString.title( this.getClass().getName() )
198                                .println( "VERSION"                     ,VERSION        )
199                                .println( "switchKey"           ,switchKey      )
200                                .println( "Other..."    ,getAttributes().getAttribute() )
201                                .fixForm().toString() ;
202        }
203}