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.hayabusa.db.DBTableModel;
021import org.opengion.fukurou.util.ErrorMessage;
022import org.opengion.fukurou.util.XHTMLTag;
023import org.opengion.fukurou.util.StringUtil;
024import org.opengion.fukurou.util.ToString;                                                      // 6.1.1.0 (2015/01/17)
025
026import static org.opengion.fukurou.util.StringUtil.nval ;
027
028import javax.servlet.http.HttpServletRequest;
029import javax.servlet.http.HttpServletResponse;
030import javax.servlet.http.HttpSession;
031import javax.servlet.ServletException;
032import java.io.IOException;
033import java.util.Enumeration;
034import java.util.Map;
035import java.util.HashMap;
036import java.util.concurrent.ConcurrentMap;                                                      // 6.4.3.3 (2016/03/04)
037import java.util.concurrent.ConcurrentHashMap;                                          // 6.4.3.1 (2016/02/12) refactoring
038
039/**
040 * submitタグを用いてページ転送するタグです(forward.jsp で使用)。
041 *
042 * 通常、forward は、ページ内転送(サーバー内部での転送)のため、別画面への遷移には
043 * 使用できません。これは、別画面では、index.jsp 等でフレーム分割する際の基準フォルダは、
044 * forward の場合、クライアントは理解していないため、もう一度先のフォルダに対する
045 * フレーム分割を行おうとするためです。
046 * (よく、index.jsp の frame タグに、src="../XXXX/query.jsp" などと、自分自身のフォルダ名を
047 * 記述したページを見かけますが、これは、フォルダをまたがる転送に、forward を使用する
048 * 為の悪い対策です。)
049 * 実際は、forward ではなく、redirect を使うべきです。redirect は、指定のアドレス要求を、
050 * 一旦クライアントに投げてそこから再度要求しなおしてもらう方式のため、このようにフォルダを
051 * またがる転送も正常に処理できます。
052 * この、commonForward タグでは、画面遷移の条件に応じて、forward か redirect の自動
053 * 判定を行い、適切に処理しています。
054 * 判定条件は、拡張子や、選択件数などを加味して以下の判定を順次テストします。
055 *
056 *   FORWARD :
057 *       アドレスが、 null(自分自身) か、.jsp を含み、"/" が入っていない場合
058 *   REDIRECT:
059 *       アドレスが、.jsp を含まないか、
060 *       それ以外(.jsp を含み、"/" も含む)で、選択数が1件のみの場合
061 *       もしくはuseRedirectCheck="false"の場合
062 *   COUNT_0 :
063 *       それ以外で、選択数が0件の場合
064 *   COUNT_N :
065 *       それ以外で、選択数が1件以上の場合、または、その他。
066 *
067 * ここで、COUNT_0 の場合は、未選択エラー、COUNT_N は、複数選択エラーを自動的に返します。
068 *
069 * @og.formSample
070 * ●形式:<og:commonForward />
071 * ●body:なし
072 *
073 * ●Tag定義:
074 *   <og:commonForward
075 *       dbkeys             【TAG】DBキーをCSV形式でセットします
076 *       tableId            【TAG】(通常は使いません)sessionから所得する DBTableModelオブジェクトの ID
077 *       useRedirectCheck   【TAG】非選択状態の場合にforwardを許可するかどうか[true/false]を指定します(初期値:true)
078 *       useRedirectHidden  【TAG】redirectの処理時に、hiddenパラメータを転送するかどうか[true:する/false:しない]指定します(初期値:false)。
079 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
080 *   />
081 *
082 * ●使用例
083 *     フォワードキャッシュによりページ転送します。
084 *     <og:commonForward dbkeys="{@dbkeys}" />
085 *
086 * @og.group 画面制御
087 *
088 * @version  4.0
089 * @author       Masaharu Endo
090 * @since    JDK5.0,
091 */
092public class CommonForwardTag extends CommonTagSupport {
093        /** このプログラムのVERSION文字列を設定します。   {@value} */
094        private static final String VERSION = "6.4.5.2 (2016/05/06)" ;
095        private static final long serialVersionUID = 645220160506L ;
096
097        // 3.5.5.3 (2004/04/09) 共通アドレスで指定することで、クライアントキャッシュを有効利用する。
098        private static final String DUMMY_HTML  = "/" + HybsSystem.getContextName() + "/jsp/common/dummy.html";
099
100        // 3.8.5.1 (2006/04/28) dbkeys が null の場合に全件取得するかどうかを COMMON_FORWARD_DBKEYS_NULL_ALL で指定します。
101
102        private static final int FORWARD  = 0;
103        private static final int REDIRECT = 1;
104        private static final int COUNT_0  = 2;
105        private static final int COUNT_N  = 3;
106
107        // 3.5.5.2 (2004/04/02) 選択行が、1行のみか、そうでないか
108        private int rowCount = -1;
109
110        private int     rowNo    = -1;
111
112        // 3.5.5.5 (2004/04/23) URLに連結するDBTableModelのカラムをCSV形式で指定します。
113        private String  dbkeys          ;
114
115        // 3.5.5.8 (2004/05/20) submitタグの keys,vals を扱う 仮想リクエストMap
116        private String  tableIdTemp     ;
117        private String  dbkeysTemp      ;
118        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
119        private final transient ConcurrentMap<String,String> submitRequestMap = new ConcurrentHashMap<>();
120        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
121        private final transient ConcurrentMap<String,String> submitTableMap       = new ConcurrentHashMap<>();
122
123        // 4.0.0.0 (2007/11/09) 非選択状態でのforwardのための属性追加
124        private boolean isRedirectCheck         = true;
125
126        // 6.2.4.0 (2015/05/15) redirectの処理時に、hiddenパラメータを転送するかどうか[true:する/false:しない]
127        // 互換性の関係で、初期値は、false にします。
128        private boolean isRedirectHidden        ;
129
130        /**
131         * デフォルトコンストラクター
132         *
133         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
134         */
135        public CommonForwardTag() { super(); }          // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
136
137        /**
138         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
139         *
140         * @og.rev 3.3.1.1 (2003/07/03) URLにリクエスト情報をURLエンコードして追加します。
141         * @og.rev 3.5.5.2 (2004/04/02) フォルダ外転送時は、1行以外選択は、エラーとします。
142         * @og.rev 3.5.5.3 (2004/04/09) デバッグ時は、転送しないようにします。
143         * @og.rev 3.8.0.4 (2005/08/08) requestUrlEncode 廃止
144         * @og.rev 3.8.0.8 (2005/10/03) dbkeys が null の場合に全件取得していた処理を復活します。
145         * @og.rev 4.0.0.0 (2007/11/09) 非選択状態からの遷移を許可するフラグを追加(11/12に振り分け処理をselectResponseMethodに移動)
146         * @og.rev 5.0.0.2 (2009/09/15) XSS対応⇒チェックする
147         * @og.rev 5.3.6.0 (2011/06/01) エラーメッセージ変更(URLの振り分け処理時に...のメッセージは出力しない)
148         * @og.rev 6.2.4.0 (2015/05/15) useRedirectHidden 属性追加
149         *
150         * @return      後続処理の指示
151         */
152        @Override
153        public int doEndTag() {
154                debugPrint();           // 4.0.0 (2005/02/28)
155
156                // useXssCheck( false ); // 5.0.0.2 (2009/09/15)
157
158                final HttpServletRequest request  = ((HttpServletRequest)getRequest());
159                final HttpSession session = pageContext.getSession();
160                String page = getForwardURI( request, session );
161
162                // 3.5.5.8 (2004/05/20) 内部仮想リクエストMap より値を取得
163                dbkeys = nval( getSubmitRequestParameter( dbkeysTemp ),dbkeys );
164
165                final HttpServletResponse response = (HttpServletResponse)pageContext.getResponse();
166
167                String errMsgKey = null;
168                try {
169
170                        // 3.8.0.8 (2005/10/03) dbkeys が null の場合に全件取得していた処理を復活します。
171                        // 6.2.4.0 (2015/05/15) dbkeys != null の場合しか、[]付のパラメータを処理できなかった。
172                        if( rowCount == 1 && ( dbkeys != null || !submitTableMap.isEmpty() ) ) {                // 6.3.9.0 (2015/11/06) size() == 0 判定は、isEmpty() に置き換え可能
173                                page = XHTMLTag.addUrlEncode( page,getTableUrlData() );
174                        }
175
176                        final String url = response.encodeRedirectURL( page );
177                        // 3.8.0.8 (2005/10/03) GET時の URL の長さ制限チェック(最大文字数は 2,083 文字)
178                        if( url != null && url.length() >= HybsSystem.MAX_GET_LENGTH ) {
179                                final String errMsg = "GET時の URL の長さは,最大2,083 文字です。"
180                                                        + " URL.length=" + url.length() + " , MAX_LENGTH=" + HybsSystem.MAX_GET_LENGTH ;
181                                throw new HybsSystemException( errMsg );
182                        }
183
184                        // 6.4.9.1 (2016/08/05) Avoid declaring a variable if it is unreferenced before a possible exit point.
185                        final int flag = selectResponseMethod( page );
186                        switch( flag ) {
187                                case FORWARD:   if( isDebug() ) { jspPrint( "FORWARD URL = [" + url + "]" ); }
188                                                                else { pageContext.forward( url ); }
189                                                                break;
190                                case REDIRECT:  // url = requestUrlEncode( url );               // 3.8.0.4 (2005/08/08)
191                                                                if( isDebug() ) { jspPrint( "REDIRECT URL = [" + url + "]" ); }
192                                                                else { response.sendRedirect( url ); }
193                                                                break;
194                                case COUNT_0:
195                                                                errMsgKey = "ERR0028" ;  // 選択されていません。もう一度、選択しなおして下さい。
196                                                                break;
197                                default: errMsgKey = "ERR0029" ;        // 複数選択されました。1件のみ選択しなおして下さい。
198                                                                break;
199                        }
200
201                } catch( final IOException ex ) {
202                        // 5.3.6.0 (2011/06/01) エラーメッセージ表示変更
203                        final String errMsg = ex.getMessage();                                  // 5.1.8.0 (2010/07/01) errMsg 修正
204                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
205                } catch( final ServletException ex ) {
206                        // 5.3.6.0 (2011/06/01) エラーメッセージ表示変更
207                        final String errMsg = ex.getMessage();                                  // 5.1.8.0 (2010/07/01) errMsg 修正
208                        throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
209                }
210
211                // 3.5.5.2 (2004/04/02) フォルダ外転送時は、1行以外選択は、エラーとします。
212                if( errMsgKey != null ) {
213                        final ErrorMessage errMsg = new ErrorMessage( "Row Count Error Maximal Error!" );
214                        errMsg.addMessage( 0,ErrorMessage.NG,errMsgKey );
215
216                        jspPrint( TaglibUtil.makeHTMLErrorTable( errMsg,getResource() ) );
217                }
218
219                return SKIP_PAGE ;              // ページの残りの処理を行わない。
220        }
221
222        /**
223         * タグリブオブジェクトをリリースします。
224         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
225         *
226         * @og.rev 3.5.5.2 (2004/04/02) 新規追加(rowCount,useTableData)
227         * @og.rev 3.5.5.5 (2004/04/23) URLに連結するDBTableModelのカラムをCSV形式で指定します。
228         * @og.rev 3.8.5.1 (2006/04/28) URLに連結するDBTableModelのカラムを[カラム]形式で指定します。
229         * @og.rev 6.2.4.0 (2015/05/15) useRedirectHidden 属性追加
230         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
231         */
232        @Override
233        protected void release2() {
234                super.release2();
235                rowCount     = -1;
236                rowNo            = -1;
237                dbkeys           = null;                // 3.5.5.5 (2004/04/23)
238                submitRequestMap.clear();               // 6.4.3.3 (2016/03/04)
239                submitTableMap.clear();                 // 6.4.3.3 (2016/03/04)
240                tableIdTemp                     = null;         // 3.5.5.8 (2004/05/20)
241                dbkeysTemp                      = null;         // 3.5.5.8 (2004/05/20)
242                isRedirectCheck         = true;         // 4.0.0.0 (2007/11/12)
243                isRedirectHidden        = false;        // 6.2.4.0 (2015/05/15)
244        }
245
246        /**
247         * フォワード先URIを取得します。
248         *
249         * @og.rev 3.1.2.0 (2003/04/07) ソースコード中の固定値を、定義ファイルを使用するように変更する。
250         * @og.rev 3.1.4.1 (2003/04/21) request.getQueryString() をaddUrlEncodeしている箇所を削除。
251         * @og.rev 3.1.7.0 (2003/05/02) コマンド RENEW で、forward した場合に、result.jsp に遷移するように修正。
252         * @og.rev 3.1.7.0 (2003/05/02) 画面IDのセットで、自画面を、BACK_GAMENID 、飛び先を、GAMENID にする。
253         * @og.rev 3.1.8.0 (2003/05/16) SubmitData クラスを利用するように変更。
254         * @og.rev 3.3.1.1 (2003/07/03) ForwardManager クラスの廃止。飛び先のキャッシュを廃止します。
255         * @og.rev 3.5.5.2 (2004/04/02) 選択行の件数を設定しておきます。
256         * @og.rev 3.5.5.3 (2004/04/09) dummy.html を static final で絶対パス指定します。
257         * @og.rev 3.5.5.4 (2004/04/15) メソッド内で使用していない、gamenId,jspID 変数を削除します。
258         * @og.rev 3.5.5.5 (2004/04/23) 余計なボタン関連情報を転送しない為に、キーを変更します。
259         * @og.rev 3.5.5.5 (2004/04/23) SubmitTag の keys,vals 属性で指定した値のみ、転送します。
260         * @og.rev 3.5.5.8 (2004/05/20) SubmitTag の keys,vals 属性で指定した値を、内部仮想リクエスト Mapにセットします。
261         * @og.rev 3.7.0.1 (2005/01/31) リクエスト変数に選択された件数を追加
262         * @og.rev 3.7.0.3 (2005/03/01) 指定の行番号まで画面をスクロールさせる機能を追加。
263         * @og.rev 3.8.0.8 (2005/10/03) BACK_GAMENID があれば BACK_ROW を追加する。
264         * @og.rev 3.8.5.1 (2006/04/28) vals="[カラム名]" という引数を処理できる機能を追加。
265         * @og.rev 5.1.8.0 (2010/07/01) VIEWの場合も、直前のJSPに遷移する。
266         * @og.rev 6.2.4.0 (2015/05/15) useRedirectHidden 属性追加
267         * @og.rev 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。
268         * @og.rev 6.4.5.2 (2016/05/06) UPLOADから呼ばれた場合は、RESET  は、command="RENEW" , displayMsg=" " にします。
269         *
270         * @param       request HttpServletRequestオブジェクト
271         * @param       session HttpSessionオブジェクト
272         *
273         * @return      フォワード先URI
274         * @og.rtnNotNull
275         */
276        private String getForwardURI( final HttpServletRequest request,
277                                                                  final HttpSession        session ) {
278
279                final String[] rows   = request.getParameterValues( HybsSystem.ROW_SEL_KEY );
280
281                // 4.0.0 (2007/05/16) query.jsp で複数command 時の処理修正
282                String   cmd  = request.getParameter( "command" );
283                final String[] cmds = request.getParameterValues( "command" );
284                if( cmds != null && cmds.length > 1 ) {
285                        for( int i=0; i<cmds.length; i++ ) {
286                                if( ! "NEW".equals( cmds[i] ) ) {
287                                        cmd = cmds[i]; break;   // NEW でない、最初の一つ
288                                }
289                        }
290                        // すべてが NEW の場合は、単体(getParameter) が NEW なので素通りでよい。
291                }
292
293                // 3.5.5.2 (2004/04/02) 選択行の件数
294                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
295                if( rows == null ) {
296                        rowCount = 0;
297                 }
298                else {
299                        rowCount = rows.length;
300                        rowNo = Integer.parseInt( rows[0] );
301                }
302                // 3.7.0.1 (2005/01/31) リクエスト変数に選択された件数を追加
303                setRequestAttribute( "ROW_COUNT",String.valueOf( rowCount ) );
304
305                if( cmd == null || cmd.isEmpty() ) { cmd = "INIT"; }
306                final String forwardPage;
307
308                final String backPage = (String)session.getAttribute( HybsSystem.FORWARD_PAGE_KEY );
309                String command  = cmd;          // 3.5.5.5 (2004/04/23)
310                int    pagePlus = 0;
311
312                // コマンドパラメータにより振分け
313                // 5.1.8.0 (2010/07/01) VIEWの場合も、直前のJSPに遷移する。
314                if( "FIRST,PREV,NEXT,LAST,VIEW".indexOf( cmd ) >= 0 ) {
315                        forwardPage = backPage;
316                } else if( "NEW,RENEW".indexOf( cmd ) >= 0 ) {
317                        // 初期値
318                        forwardPage = "result.jsp";
319                } else if( "INIT".equals( cmd ) ) {
320                        forwardPage = DUMMY_HTML;                       // 3.5.5.3 (2004/04/09)
321                } else {
322                        // 共有オブジェクト検索
323
324                        // リンク元コマンド名取得
325                        // 3.5.5.5 (2004/04/23) 余計なボタン関連情報を転送しない為に、キーを変更します。
326                        command = request.getParameter( HybsSystem.NO_XFER_KEY + cmd + "CMD" );
327
328                        // 3.7.0.3 (2005/03/01) 指定の行番号まで画面をスクロールさせる機能を追加。
329                        if( rows != null && "ENTRY".equals( command ) ) {
330                                setRequestCacheData( "SEL_ROW",String.valueOf( rowNo ) );
331                        }
332
333                        if( "RESET".equals( command ) ) { // RESET 時
334                                forwardPage = "result.jsp";
335
336                                // 6.4.5.2 (2016/05/06) UPLOADから呼ばれた場合は、RESET  は、command="RENEW" , displayMsg=" " にします。
337                                if( Boolean.parseBoolean( request.getParameter( HybsSystem.USE_UPLOAD_KEY ) ) ) {
338                                        command = "RENEW";
339                                        setRequestAttribute( "displayMsg"," " );                // RESETなので、メッセージは出さない。
340                                        setRequestCacheData( "SEL_ROW"   ,null );               // RENEWで戻るため、以前に行選択があったら、そこに戻ってしまうため、クリアしておく。
341                                }
342                        }
343                        else {
344                                // リンク先取得
345                                forwardPage = request.getParameter( HybsSystem.NO_XFER_KEY + cmd );
346                                // INSERTとCOPYの場合のみ
347                                if( "INSERT".equals( command ) || "COPY".equals( command ) ) {
348                                        if( rows != null ) { pagePlus = rows.length; }
349                                }
350                        }
351                }
352
353                if( ! forwardPage.equals( backPage ) ) {
354                        session.setAttribute( HybsSystem.REVIEW_PAGE_KEY , backPage );
355                }
356                session.setAttribute( HybsSystem.FORWARD_PAGE_KEY, forwardPage );
357
358                // 3.5.5.5 (2004/04/23) SubmitTag の keys,vals 属性で指定した値のみ、転送します。
359                // 6.0.2.5 (2014/10/31) char を append する。
360                final StringBuilder strURL = new StringBuilder( BUFFER_MIDDLE )
361                        .append( '&' ).append( "command"  ).append( '=' ).append( command )
362                        .append( '&' ).append( "pagePlus" ).append( '=' ).append( String.valueOf( pagePlus ) );
363
364                final String btnKey = HybsSystem.NO_XFER_KEY + cmd + "KEY_" ;
365                final int    keylen = btnKey.length() ;
366
367                final Enumeration<?> enm = getParameterNames();         // 4.3.3.6 (2008/11/15) Generics警告対応
368
369                // 6.2.4.0 (2015/05/15) useRedirectHidden 属性追加
370                final Map<String,String> hiddenMap = new HashMap<>();
371                boolean isGamenIdFlag = false;
372
373                while( enm.hasMoreElements() ) {
374                        final String key = (String)( enm.nextElement() );
375                        // 3.5.5.5 (2004/04/23) 余計な情報を転送しない様に、キーを選別します。
376                        if( key != null && key.startsWith( btnKey ) ) {
377                                // 3.5.5.8 (2004/05/20) 内部の仮想リクエスト Map に設定します。
378                                final String kk = key.substring( keylen ) ;
379                                final String vv = nval( getRequestValue( key ) , "" );                  // 6.4.3.1 (2016/02/12) ConcurrentHashMap の条件は、key,val ともに、not null
380                                // 3.8.5.1 (2006/04/28) vals="[カラム名]" という引数を処理できる機能を追加。
381                                if( vv.length() > 2 && vv.charAt(0) == '[' && vv.charAt(vv.length()-1) == ']' ) {
382                                        submitTableMap.put( kk,vv.substring( 1,vv.length()-1 ));
383                                }
384        //                      else if( "dbkeys".equals( kk ) ) {
385        //                              submitRequestMap.put( kk,vv );
386        //                      }
387                                else {
388                                        submitRequestMap.put( kk,vv );
389                                        strURL.append( '&' )                                    // 6.0.2.5 (2014/10/31) char を append する。
390                                                .append( kk ).append( '=' )                     // 6.0.2.5 (2014/10/31) char を append する。
391                                                .append( StringUtil.urlEncode( vv ) );
392                                }
393
394                                // 3.8.0.8 (2005/10/03) BACK_GAMENID があれば BACK_ROW を追加する。
395                                if( "BACK_GAMENID".equalsIgnoreCase( kk ) && rowNo >= 0 ) {
396                                        strURL.append( "&BACK_ROW=" ).append( rowNo );
397                                }
398
399                                // 6.2.4.0 (2015/05/15) 個別に GAMENID があれば、submitTag で指定されたはず。
400                                if( "GAMENID".equalsIgnoreCase( kk ) ) {
401                                        isGamenIdFlag = true;
402                                }
403                        }
404                        // 6.2.4.0 (2015/05/15) useRedirectHidden 属性追加
405                        // 取りあえず対象のリクエストは、Mapにセットしておきます。
406                        if( isRedirectHidden && key != null && !key.startsWith( "h_" ) && !key.startsWith( "hX_" ) ) {
407                                hiddenMap.put( key,getRequestValue( key,false ) );
408                        }
409                }
410
411                // 6.2.4.0 (2015/05/15) useRedirectHidden 属性追加
412                // 個別に GAMENID がある場合(isGamenIdFlag == true)のみ、このフラグを有効にします。
413                if( isRedirectHidden && isGamenIdFlag ) {
414                        for( final Map.Entry<String,String> entry : hiddenMap.entrySet() ) {
415                                final String key = '&' + entry.getKey() + '=';          // strURL は、必ず & で始まっている。
416                                if( strURL.indexOf( key ) < 0 ) {                               // すでに、個別定義済みのパラメータは転送しない。
417                                        strURL.append( key ).append( StringUtil.urlEncode( entry.getValue() ) );
418                                }
419                        }
420                }
421
422                return XHTMLTag.addUrlEncode( forwardPage,strURL.toString() );
423        }
424
425        /**
426         * ページを リダイレクトかフォワードか選択します。
427         * 判定条件は、拡張子や、選択件数などを加味して以下の判定を順次テストします。
428         *
429         *   FORWARD :
430         *       アドレスが、 null か、.jsp を含み、"/" が入っていない場合
431         *   REDIRECT:
432         *       アドレスが、.jsp を含まないか、それ以外(.jsp を含み、"/" も含む)で、選択数が1件のみの場合
433         *   COUNT_0 :
434         *       それ以外で、選択数が0件の場合
435         *   COUNT_N :
436         *       それ以外で、選択数が1件以上の場合、または、その他。
437         *
438         * @og.rev 3.5.5.2 (2004/04/02) 新規作成:isJspPrefix( String page ) の代用です。
439         * @og.rev 4.0.0.0 (2007/05/23) useTableData の書き換えを中止します。
440         * @og.rev 4.0.0.0 (2007/11/12) 非選択状態でもリダイレクト可能なフラグ(isRedirectCheck)を追加
441         *
442         * @param   page        判定する転送先アドレス
443         *
444         * @return  FORWARD,REDIRECT,COUNT_0,COUNT_N のうち、どれか
445         */
446        private int selectResponseMethod( final String page ) {
447                if( page == null ) { return FORWARD; }
448
449                final int adrs = page.indexOf( ".jsp" );
450
451                if( adrs >= 0 && page.lastIndexOf( '/',adrs ) < 0 ) {
452                        return FORWARD;
453                }
454                else if( adrs < 0 || !isRedirectCheck ) { // 4.0.0.0 (2007/11/12) 非選択リダイレクト許可フラグ追加
455                        return REDIRECT;
456                }
457                else if( rowCount == 1 ) {
458                        return REDIRECT;
459                }
460                else if( rowCount == 0 ) {
461                        return COUNT_0;
462                }
463                else {
464                        return COUNT_N;
465                }
466        }
467
468        /**
469         * 【TAG】(通常は使いません)sessionから所得する DBTableModelオブジェクトの ID
470         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
471         *
472         * @og.tag
473         * 表示処理後に,(内部ポインタを書き換えた)DBTableModelオブジェクトを
474         * 同じキーで、sessionに登録します。
475         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
476         *
477         * @og.rev 3.5.5.2 (2004/04/02) 新規追加
478         * @og.rev 3.5.5.8 (2004/05/20) 内部仮想リクエスト Map を参照できるようにする。
479         *
480         * @param       id テーブルID (sessionから所得する時のID)
481         */
482        public void setTableId( final String id ) {
483                // 注意:引数のリクエスト変数が無ければ、自分自身({@XXX}形式)を再セットする。
484                tableIdTemp   = nval( getRequestParameter( id ),id );
485        }
486
487        /**
488         * 指定のスコープの内部キャッシュ情報に、DBTableModel の選択された値を登録します。
489         *
490         * 複数選択行が存在する場合は、先頭行を処理します。ただし、action="APPEND"の
491         * 場合は、separator属性で指定された文字を使用して、連結します。
492         *
493         * @og.rev 3.5.5.2 (2004/04/02) 新規作成
494         * @og.rev 3.5.5.5 (2004/04/23) URLに連結するDBTableModelのカラムをCSV形式で指定します。
495         * @og.rev 3.8.0.4 (2005/08/08) dbkeys が null の場合に全件取得していた処理を中止します。
496         * @og.rev 3.8.0.8 (2005/10/03) dbkeys が null の場合に全件取得していた処理を復活します。
497         * @og.rev 3.8.5.1 (2006/04/28) vals="[カラム名]" という引数を処理できる機能を追加。
498         * @og.rev 3.8.5.1 (2006/04/28) dbkeys が null の場合に全件取得するかどうかを COMMON_FORWARD_DBKEYS_NULL_ALL で指定します。
499         * @og.rev 4.0.0.0 (2007/05/23) tableId をこのメソッド内で求めます。
500         *
501         * @return      DBTableModelの選択された値の文字列
502         * @og.rtnNotNull
503         */
504        private String getTableUrlData() {
505                final String tableId = nval( getSubmitRequestParameter( tableIdTemp ),HybsSystem.TBL_MDL_KEY );
506
507                final DBTableModel table = (DBTableModel)getSessionAttribute( tableId );
508
509                String dbkeysUrl  = "";
510                String tblkeysUrl = "";
511
512                if( table != null ) {
513                        String[] keys = null;
514                        String[] vals = null;
515                        if( dbkeys != null ) {
516                                keys = StringUtil.csv2Array( dbkeys );
517                                vals = new String[keys.length];
518                                for( int i=0; i<keys.length; i++ ) {
519                                        final int clmNo = table.getColumnNo( keys[i] );
520                                        vals[i] = table.getValue(rowNo,clmNo);
521                                }
522                        }
523
524                        dbkeysUrl = XHTMLTag.urlEncode( keys, vals );
525
526                        // 3.8.5.1 (2006/04/28) vals="[カラム名]" という引数を処理できる機能を追加。
527                        final int size = submitTableMap.size();
528                        if( size > 0 ) {
529                                @SuppressWarnings("rawtypes")
530                                final Map.Entry[] entry = submitTableMap.entrySet().toArray( new Map.Entry[size] );
531
532                                String[] tblkeys = new String[size];
533                                String[] tblvals = new String[size];
534
535                                for( int i=0; i<size; i++ ) {
536                                        tblkeys[i]  = (String)entry[i].getKey();
537                                        final String temp = (String)entry[i].getValue();
538                                        final int clmNo = table.getColumnNo( temp );
539                                        tblvals[i] = table.getValue( rowNo,clmNo );
540                                }
541                                tblkeysUrl = XHTMLTag.urlEncode( tblkeys, tblvals );
542                        }
543                }
544
545                String rtn = dbkeysUrl;
546
547                if( tblkeysUrl.length() > 0 ) {
548                        if( rtn.length() > 0 ) {
549                                rtn += "&" + tblkeysUrl;
550                        }
551                        else {
552                                rtn = tblkeysUrl ;
553                        }
554                }
555                return rtn ;
556        }
557
558        /**
559         * 【TAG】DBキーをCSV形式でセットします。
560         *
561         * @og.tag
562         * URI の引数にセットするキーを CSV形式でセットします。
563         * ここの指定は,DBTableModel 上のデータを取り込みます。
564         *
565         * @og.rev 3.5.5.5 (2004/04/23) URLに連結するDBTableModelのカラムをCSV形式で指定します。
566         * @og.rev 3.5.5.8 (2004/05/20) 内部仮想リクエスト Map を参照できるようにする。
567         *
568         * @param       key DBキー(CSV形式)
569         */
570        public void setDbkeys( final String key ) {
571                // 注意:引数のリクエスト変数が無ければ、自分自身({@XXX}形式)を再セットする。
572                dbkeysTemp = nval( getRequestParameter( key ),key ) ;
573        }
574
575        /**
576         * 内部の仮想リクエスト Map より、リクエストパラメータより値を設定します。
577         *
578         * submitタグの keys,vals より送信されたリクエスト値は、このクラスで
579         * 処理され、内部の仮想リクエスト Map に保存されます。
580         * 通常のリクエスト設定時点では、この値は取り出すことが出来ない為、
581         * Map に保存(getForwardURI 処理で設定)された後に、引き出します。
582         *
583         * @og.rev 3.5.5.8 (2004/05/20) 新規作成
584         *
585         * @param       key     DBキー(CSV形式)
586         *
587         * @return      仮想リクエスト Map を反映させた、リクエスト値
588         */
589        private String getSubmitRequestParameter( final String key ) {
590                String rtn = key;
591
592                // 変数が "{@XXXX}" の場合のみ対応
593                if( key != null && key.startsWith( "{@" ) && key.charAt(key.length()-1) == '}' ) {
594                        rtn = submitRequestMap.get( key.substring( 2,key.length()-1 ) );
595                }
596
597                return rtn;
598        }
599
600        /**
601         * 【TAG】非選択状態の場合にforwardを許可するかどうか[true/false]を指定します(初期値:true)。
602         *
603         * @og.tag
604         * 初期値はtrueが設定されています
605         * falseにすると許可されます
606         *
607         * @og.rev 4.0.0.0 (2007/11/09) 新規作成
608         *
609         * @param       flag    非選択状態のforward許可 [true:不許可/false:許可]
610         */
611        public void setUseRedirectCheck(final String flag) {
612                isRedirectCheck = nval( getRequestParameter( flag ),isRedirectCheck );
613        }
614
615        /**
616         * 【TAG】redirectの処理時に、hiddenパラメータを転送するかどうか[true:する/false:しない]を指定します(初期値:false)。
617         *
618         * @og.tag
619         * submitTag で、gamenId を指定すると、redirect されます。
620         * その場合、従来の画面では、hidden 属性が転送されていなかったため、
621         * 個別に keys,vals で指定する必要がありました。
622         * hidden で記述した値は、redirect でも転送できるようにします。
623         * なお、個別定義済みのパラメータがあり、hiddenパラメータを同じキーの場合は、
624         * 個別パラメータを優先し、hiddenパラメータは転送しません。
625         *
626         * 本来は、gamenId指定の submit の場合でも、必要最小限の値のみ転送すべきで、
627         * この値を true にするのは、過去のJSPソースを、修正せずに使いたいケースに限定してください。
628         * 互換性の関係で、初期値は、false にします。
629         *
630         * @og.rev 6.2.4.0 (2015/05/15) 新規作成
631         *
632         * @param       flag    非選択状態のforward許可 [true:不許可/false:許可]
633         */
634        public void setUseRedirectHidden(final String flag) {
635                isRedirectHidden = nval( getRequestParameter( flag ),isRedirectHidden );
636        }
637
638        /**
639         * このオブジェクトの文字列表現を返します。
640         * 基本的にデバッグ目的に使用します。
641         *
642         * @return このクラスの文字列表現
643         * @og.rtnNotNull
644         */
645        @Override
646        public String toString() {
647                return ToString.title( this.getClass().getName() )
648                                .println( "VERSION"                             ,VERSION                        )
649                                .println( "rowCount"                    ,rowCount                       )
650                                .println( "rowNo"                               ,rowNo                          )
651                                .println( "dbkeys"                              ,dbkeys                         )
652                                .println( "tableIdTemp"                 ,tableIdTemp            )
653                                .println( "dbkeysTemp"                  ,dbkeysTemp                     )
654                                .println( "useRedirectCheck"    ,isRedirectCheck        )       // 6.2.4.0 (2015/05/15)
655                                .println( "useRedirectHidden"   ,isRedirectHidden       )       // 6.2.4.0 (2015/05/15)
656                                .println( "Other..."                    ,getAttributes().getAttribute() )
657                                .fixForm().toString() ;
658        }
659}