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.common.HybsSystem;
019import org.opengion.hayabusa.common.HybsSystemException;
020import org.opengion.fukurou.system.LogWriter;
021import org.opengion.fukurou.system.HybsConst;                                   // 6.4.5.2 (2016/05/06)
022import org.opengion.fukurou.util.FileUtil;                                              // 6.4.5.2 (2016/05/06)
023import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
024import org.opengion.fukurou.util.StringUtil ;                                   // 6.2.0.0 (2015/02/27)
025
026import static org.opengion.fukurou.util.StringUtil.nval;                // 5.9.10.5 (2016/07/22)
027
028import javax.servlet.ServletRequest ;
029import javax.servlet.http.HttpServletRequest ;
030
031/**
032 * BODY部に記述されたエンジン固有の文字列({@XXXX}など)を、
033 * ユーザー情報のエンコーディングに変換するタグです。
034 *
035 * XML形式で 日本語コードのパースが、JSPエンジン(Tomcat)でサポート
036 * されるまでの、暫定的なタグです。
037 * なお、このタグの内部に存在するカスタムタグは、先に実行されるため
038 * 漢字コードは、変換されません。
039 *
040 * ※ 6.3.1.0 (2015/06/28) caseKey、caseVal、caseNN、caseNull、caseIf 属性追加
041 *
042 * @og.formSample
043 * ●形式:<og:text >・・・</og:text>
044 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
045 *
046 * ●Tag定義:
047 *   <og:text
048 *       value              【TAG】value 値に直接書かれたコードを出力します
049 *       include            【TAG】動的にファイルを include します(初期値:null)
050 *       usePrintOut        【TAG】デバッグ用に、value 値を System.out.println に 出力するかどうか(初期値:false) 6.9.3.0 (2018/03/26)
051 *       xssCheck           【TAG】リクエスト情報の HTMLTag開始/終了文字(><) 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
052 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
053 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
054 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
055 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
056 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
057 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
058 *   >   ... Body ...
059 *   </og:text>
060 *
061 * ●使用例
062 *      ・<og:text >
063 *            <p>あいおえお:<input name="PN" value="{@PN}" /> </p>
064 *        </og:text>
065 *      ・<og:text value="あいうえお" />
066 *
067 *     動的にファイルを include することが出来ます。
068 *      ・<og:text include="{@query}.txt" />
069 *
070 * @og.group 画面部品
071 *
072 * @version  4.0
073 * @author   Kazuhiko Hasegawa
074 * @since    JDK5.0,
075 */
076public class TextTag extends CommonTagSupport {
077        /** このプログラムのVERSION文字列を設定します。   {@value} */
078        private static final String VERSION = "6.9.3.0 (2018/03/26)" ;
079        private static final long serialVersionUID = 693020180326L ;
080
081        private String  value           ;
082        private boolean useInclude      ;
083        private boolean usePrintOut     ;       // 6.9.3.0 (2018/03/26)
084
085        private boolean xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );        // 5.9.10.5 (2016/07/22) XSS対策
086
087        /**
088         * デフォルトコンストラクター
089         *
090         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
091         */
092        public TextTag() { super(); }           // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
093
094        /**
095         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
096         *
097         * @og.rev 6.3.1.0 (2015/06/28) caseKey、caseVal、caseNN、caseNull、caseIf 属性追加
098         *
099         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
100         */
101        @Override
102        public int doStartTag() {
103                // 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
104                return useTag() && !useInclude && value == null
105                                        ? EVAL_BODY_BUFFERED            // Body を評価する。( extends BodyTagSupport 時)
106                                        : SKIP_BODY ;                           // Body を評価しない
107        }
108
109        /**
110         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
111         *
112         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更
113         * @og.rev 3.0.0.0 (2002/12/25) StringUtil#changeString 廃止
114         * @og.rev 3.1.1.0 (2003/03/28) ボディの内容を取得する処理を、CommonTagSupport で行う。
115         * @og.rev 4.0.0.0 (2007/10/12) 処理中にエラーを発生させないようにしする。
116         * @og.rev 6.3.1.0 (2015/06/28) caseKey、caseVal、caseNN、caseNull、caseIf 属性追加
117         * @og.rev 5.9.10.5 (2016/07/22) XSS対策
118         *
119         * @return      後続処理の指示(SKIP_BODY)
120         */
121        @Override
122        public int doAfterBody() {
123                // 6.3.1.0 (2015/06/28) caseKey、caseVal、caseNN、caseNull、caseIf 属性追加
124                // 4.0.0.0 (2007/10/12) 処理中にエラーを発生させない
125                try {
126                        useXssCheck( xssCheck );                // 5.9.10.5 (2016/07/22)
127                        value = getBodyString();
128                }
129                catch( final HybsSystemException ex ) { // 主に、UserInfo が見つからない場合
130                        value = getBodyContent().getString() ;
131                }
132
133                return SKIP_BODY ;
134        }
135
136        /**
137         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
138         *
139         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
140         * @og.rev 6.3.1.0 (2015/06/28) caseKey、caseVal、caseNN、caseNull、caseIf 属性追加
141         * @og.rev 6.9.0.2 (2018/02/13) debug="true" で、System.out.println( value ) を出します。
142         * @og.rev 6.9.3.0 (2018/03/26) debug="true" ではなく、専用属性の usePrintOut で出力を制御します。
143         *
144         * @return      後続処理の指示
145         */
146        @Override
147        public int doEndTag() {
148                if( usePrintOut ) {
149                        System.out.println( "TextTag=" + value );               // 6.9.3.0 (2018/03/26)
150                }
151                else {
152                        debugPrint();                   // 4.0.0 (2005/02/28)
153                        if( useTag() ) {                // 6.3.1.0 (2015/06/28)
154                                jspPrint( value );
155                        }
156                }
157                return EVAL_PAGE ;
158        }
159
160        /**
161         * タグリブオブジェクトをリリースします。
162         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
163         *
164         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
165         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
166         * @og.rev 5.9.10.5 (2016/07/22) xssCheck追加
167         * @og.rev 6.9.3.0 (2018/03/26) usePrintOut 新規追加
168         *
169         */
170        @Override
171        protected void release2() {
172                super.release2();
173                value           = null;
174                useInclude      = false;
175                usePrintOut     = false;        // 6.9.3.0 (2018/03/26)
176                xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );        // 5.9.10.5 (2016/07/22)
177        }
178
179        /**
180         * 【TAG】value 値に設定します。
181         *
182         * @og.tag
183         * ここで、value に設定した場合は、BODY 部は無視されます。
184         * なお、このタグでは、エラー発生時でも継続して処理を続けられるようにします。
185         * error.jsp などのエラー処理画面で、このタグを使用するケースがある為です。
186         *
187         *  <og:text value="あいうえお" />
188         *
189         * @og.rev 2.2.0.0 (2002/12/17) 中国語(国際化)対応 エンコードの取得方法変更
190         * @og.rev 3.0.0.0 (2002/12/25) StringUtil#changeString 廃止
191         * @og.rev 4.0.0.0 (2005/12/31) エラー発生時でも異常終了させずに処理を続けます。
192         *
193         * @param   val 設定値
194         */
195        public void setValue( final String val ) {
196                if( !useInclude ) {
197                        try {
198                                value = getRequestParameter( val );
199                        }
200                        catch( final HybsSystemException ex ) {
201                                value = val ;
202                                LogWriter.log( "val=" + val + " [" + ex.getMessage() + "]" );
203                        }
204                }
205        }
206
207        /**
208         * 【TAG】動的にファイルを include します。
209         *
210         * @og.tag
211         * 指定のファイル名は、自身のディレクトリからの相対パスで表されます。
212         *
213         * @og.rev 4.0.0.0 (2007/05/25) 新規追加
214         * @og.rev 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更
215         * @og.rev 6.4.5.2 (2016/05/06) fukurou.util.FileString から、fukurou.util.FileUtil に移動。
216         *
217         * @param   file ファイル名
218         */
219        public void setInclude( final String file ) {
220                useInclude = true;
221
222                final String relativePath = getRequestParameter( file );
223                final String resourcePath = getContextRelativePath(getRequest(), relativePath);
224                final String realPath = HybsSystem.url2dir( resourcePath.substring(1) );
225
226                // 6.4.5.1 (2016/04/28) FileStringのコンストラクター変更
227                value = FileUtil.getValue( realPath , HybsConst.UTF_8 );                        // 6.4.5.2 (2016/05/06)
228        }
229
230        /**
231         * 【TAG】デバッグ用に、value 値を System.out.println に 出力するかどうか[true/false]を設定します。
232         *
233         * @og.tag
234         * DOS窓に出力するので、サービス化していない場合のデバッグ用の機能です。
235         * Tomcat内のJSPで、繰返し処理を行っているような場合、処理時間が長い場合、HTMLとしての
236         * レスポンスは、すべての処理が完了するまで戻ってこないため、進捗状況がわかりません。
237         * そこで、DOS窓上に、System.out.printlnとして、value値を出力します。
238         * このフラグを true にセットした場合には、debugも、useTag(タグの使用)も効果は無く、
239         * value値も JSPには表示しません。
240         * 初期値は、(false:出力しない) です。
241         *
242         * @og.rev 6.9.3.0 (2018/03/26) usePrintOut 新規追加
243         *
244         * @param       flag    System.out.println に 出力するかどうか [true:する/false:しない]
245         */
246        public void setUsePrintOut( final String flag ) {
247                usePrintOut = nval( getRequestParameter( flag ),usePrintOut );
248        }
249
250        /**
251         * 【TAG】リクエスト情報の HTMLTag開始/終了文字(><) 存在チェックを実施するかどうか[true/false]を設定します
252         *              (初期値:USE_XSS_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK}])。
253         *
254         * @og.tag
255         * クロスサイトスクリプティング(XSS)対策の一環としてless/greater than signについてのチェックを行います。
256         * (><) が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。
257         * (初期値:システム定数のUSE_XSS_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK}])。
258         *
259         * @og.rev 5.9.10.5 (2016/07/22) xssCheck
260         *
261         * @param       flag    XSSチェック [true:する/false:しない]
262         * @see         org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
263         */
264        public void setXssCheck( final String flag ) {
265                xssCheck = nval( getRequestParameter( flag ),xssCheck );
266        }
267
268        /**
269         * このオブジェクトの文字列表現を返します。
270         * 基本的にデバッグ目的に使用します。
271         *
272         * @og.rev 6.9.0.2 (2018/02/13) useTag 属性の値も表示に加えます。
273         *
274         * @return このクラスの文字列表現
275         * @og.rtnNotNull
276         */
277        @Override
278        public String toString() {
279                return ToString.title( this.getClass().getName() )
280                                .println( "VERSION"             ,VERSION        )
281                                .println( "useTag"              ,useTag()       )                                       // 6.9.0.2 (2018/02/13)
282                                .println( "value"               ,value          )
283                                .println( "Other..."    ,getAttributes().getAttribute() )
284                                .fixForm().toString() ;
285        }
286
287        /**
288         * 動的にファイルを include する為の、コンテキストパスを求めます。
289         *
290         * 指定のファイル名は、自身のディレクトリからの相対パスで表されます。
291         *
292         * @og.rev 4.0.0.0 (2007/05/25) 新規追加
293         * @og.rev 4.0.0.0 (2007/11/30) if の評価方法を変更します。
294         *
295         * @param       request                 ServletRequestオブジェクト
296         * @param       relativePath    ファイル名
297         *
298         * @return      コンテキストパス
299         */
300        private String getContextRelativePath( final ServletRequest request,final String relativePath ) {
301                // 6.1.0.0 (2014/12/26) refactoring
302                if( StringUtil.startsChar( relativePath , '/' )                         // 6.2.0.0 (2015/02/27) 1文字 String.startsWith
303                        || !(request instanceof HttpServletRequest) ) {
304                                return relativePath ;
305                }
306
307                final HttpServletRequest hrequest = (HttpServletRequest) request;
308                String uri = (String)request.getAttribute("javax.servlet.include.servlet_path");
309                if( uri != null && uri.lastIndexOf('/') >= 0 ) {
310                        final String pathInfo = (String)request.getAttribute("javax.servlet.include.path_info");
311                        if( pathInfo == null ) {
312                                uri = uri.substring(0, uri.lastIndexOf('/'));
313                        }
314                }
315                else {
316                        uri = hrequest.getServletPath();
317                        if( uri.lastIndexOf('/') >= 0 ) {
318                                uri = uri.substring(0, uri.lastIndexOf('/'));
319                        }
320                }
321                return uri + '/' + relativePath;
322        }
323}