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.hayabusa.resource.GUIInfo;
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
028/**
029 * フレームを作成するHTML拡張タグで、引数の受け渡しが可能です。
030 *
031 * @og.formSample
032 * ●形式:<og:frame src="…" name="…" />
033 * ●body:なし
034 *
035 * ●Tag定義:
036 *   <og:frame
037 *       src              ○【HTML】フレームに表示するソースファイルを指定します(必須)。
038 *       name             ○【HTML】フレーム名を指定します(例:QUERY,RESULT,CONTENTS など)(必須)。
039 *       changeGamen        【TAG】ソース指定の画面を変更します
040 *       keys               【TAG】引数を指定します
041 *       dbTable            【TAG】前ページで選択したデータ列の情報を次のページに渡すかどうか[true/false]を指定します(初期値:false)
042 *       longdesc           【HTML】フレームに関する詳しい説明のあるURL(lobgdesc)を指定します
043 *       forceEnc           【TAG】(通常は使いません) valsの値が[で開始している場合でもURLEncodeを通すかを設定します(初期値:false) 5.10.15.3 (2019/09/27)
044 *       id                 【HTML】要素に対して固有の名前(id)をつける場合に設定します
045 *       clazz              【HTML】要素に対して class 属性を設定します
046 *       title              【HTML】要素に対する補足的情報(title)を設定します
047 *       style              【HTML】この要素に対して適用させるスタイルシート(style)を設定します
048 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 5.7.7.2 (2014/06/20)
049 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 5.7.7.2 (2014/06/20)
050 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 5.7.7.2 (2014/06/20)
051 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 5.7.7.2 (2014/06/20)
052 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
053 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
054 *   />
055 *
056 * 【廃止】7.0.1.0 (2018/10/15) 物理削除
057 *   //  marginwidth        【廃止】フレームの左右余白サイズ(marginwidth)を指定します(HTML5廃止属性) 
058 *   //  marginheight       【廃止】フレームの上下余白サイズ(marginheight)を指定します(HTML5廃止属性)
059 *   //  noresize           【廃止】フレームサイズを変更できないよう(noresize)に指定します(HTML5廃止属性) 6.9.5.0 (2018/04/23) 物理削除
060 *   //  frameborder        【廃止】フレームの境界線(frameborder)の[0:非表示/1:表示]を指定します(初期値:1)(HTML5廃止属性) 6.9.5.0 (2018/04/23) 物理削除
061 *   //  scrolling          【廃止】スクロールバー(scrolling)の表示/非表示[auto/yes/no]を指定します(初期値:auto)(HTML5廃止属性)
062 *
063 * ●使用例:
064 *    ・一般的な例:フレーム分割する構文は、HTML準拠。リクエスト変数は各フレームまで転送されます。
065 *    <frameset>
066 *        <og:frame src="query.jsp"   name="QUERY"  />
067 *        <og:frame src="forward.jsp" name="RESULT" />
068 *    </frameset>
069 *
070 *    ・DBTableModel の値(例ではPN)を、取り出して、リクエスト変数として利用します。
071 *      現状では、commonForward タグ の useTableData="true" dbkeys="{@dbkeys}" 属性を利用します。
072 *    <frameset>
073 *        <og:frame src="query.jsp"   name="QUERY"  keys="PN" dbTable="true" />
074 *        <og:frame src="forward.jsp" name="RESULT" keys="PN" dbTable="true" />
075 *    </frameset>
076 *
077 *    ・changeGamen 属性を利用して、ソース指定の画面を切り替えます。
078 *      たとえば、jsp/index.jsp では、GAMENID属性がURLに存在する場合、直接その画面を
079 *      表示させることができます。
080 *    <frameset cols="160,*,0" frameborder="1" framespacing="1">
081 *        <og:frame src="menu/menu.jsp"    name="MENU" />
082 *        <og:frame src="GE0000/index.jsp" name="CONTENTS"
083 *                                                    changeGamen="{@GAMENID}" />
084 *    </frameset>
085 *
086 * @og.group 画面部品
087 *
088 * @version  4.0
089 * @author       Kazuhiko Hasegawa
090 * @since    JDK5.0,
091 */
092public class FrameTag extends HTMLTagSupport {
093        /** このプログラムのVERSION文字列を設定します。   {@value} */
094        private static final String VERSION = "6.9.5.0 (2018/04/23)" ;
095        private static final long serialVersionUID = 695020180423L ;
096
097        private String                  tableId         = HybsSystem.TBL_MDL_KEY;
098        private String                  changeGmn       ;
099        private String                  keys            ;
100        private transient DBTableModel table;
101        private boolean                 dbTable         ;
102
103        // 3.5.2.0 (2003/10/20) システムパラメータ の FRAME_UNDER_BAR_REQUEST_KEY_USED を使用。
104        private final boolean UNDER_BAR_KEY_USED = HybsSystem.sysBool( "FRAME_UNDER_BAR_REQUEST_KEY_USED" );
105        protected boolean useForceEnc   ;       // 5.10.15.3 (2019/09/27) 強制URLエンコード用
106
107        /**
108         * デフォルトコンストラクター
109         *
110         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
111         */
112        public FrameTag() { super(); }          // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
113
114        /**
115         * タグリブオブジェクトをリリースします。
116         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
117         *
118         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
119         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
120         * @og.rev 5.10.15.3 (2019/09/27) forceEnc追加
121         *
122         */
123        @Override
124        protected void release2() {
125                super.release2();
126                tableId         = HybsSystem.TBL_MDL_KEY;
127                changeGmn       = null;         // 4.0.0 (2005/02/28)
128                keys            = null;
129                table           = null;
130                dbTable         = false;
131                useForceEnc     = false;        // 5.10.15.3 (2019/09/27)
132        }
133
134        /**
135         * リンクを作成します。
136         *
137         * @og.rev 3.5.4.0 (2003/11/25) comand="RENEW" 時には、dbTable 属性は、強制的に false とします。
138         * @og.rev 5.9.1.2 (2015/10/23) iframeとの継承関係で、共通的に呼び出すメソッドを追加します。
139         *
140         * @return      リンクタグ文字列
141         * @og.rtnNotNull
142         */
143        @Override
144        protected String makeTag() {
145                if( changeGmn != null ) { set( "src",changeGmn ); }
146
147                final String cmd = getRequest().getParameter( "command" );
148                if( "RENEW".equals( cmd ) ) { dbTable = false; }
149
150                setIdName();
151                final String urlEnc = getUrlEncode();
152                return makeTagFrame( urlEnc );
153        }
154
155        /**
156         * リンクを作成します。
157         *
158         * @og.rev 5.9.1.2 (2015/10/23) iframeとの継承関係で、共通的に呼び出すメソッドを追加します。
159         *
160         * @param       urlEnc エンコードされたURL
161         * @return      リンクタグ文字列
162         * @og.rtnNotNull
163         */
164        protected String makeTagFrame( final String urlEnc ) {
165                return XHTMLTag.frame( getAttributes(),urlEnc );
166        }
167
168        /**
169         * id 属性 / name 属性 セット
170         *
171         * フレーム名は id 属性で登録する(XHTML) 互換性のため、
172         * id 属性と name 属性には同じ値をセットしておく。
173         *
174         */
175        private void setIdName() {
176                final String idno       = get( "id" );
177                final String name       = get( "name" );
178                if( idno == null || idno.isEmpty() ) {
179                        if( name != null && name.length() > 0 ) {
180                                set( "id", name );
181                        }
182                        else {
183                                final String errMsg = "id 属性か name 属性のどちらかは登録してください。";
184                                throw new HybsSystemException( errMsg );
185                        }
186                }
187                else {
188                        set( "name", idno );
189                }
190        }
191
192        /**
193         * keys 属性 を元に、request情報より values の値を取り込む。
194         *
195         * keys属性は キー情報がCSV形式になっている為,ばらして
196         * values属性の配列に一つづつ設定していきます。
197         *
198         * @og.rev 2.0.0.2 (2002/09/24) 検索結果の値を取り込めていなかったバグを修正。
199         * @og.rev 2.1.1.1 (2002/11/15) 選択行情報を取り込めていなかったバグを修正。
200         * @og.rev 3.4.0.3 (2003/09/10) DBTableModelへのリクエスト情報をURLに連結しないように変更。
201         * @og.rev 4.0.0.0 (2005/01/31) getParameterRows() を使用するように変更
202         * @og.rev 5.10.15.3 (2019/09/27) forceEnc追加
203         *
204         * @return      URLエンコードされた文字列
205         * @og.rtnNotNull
206         */
207//      private String getUrlEncode() {
208        protected String getUrlEncode() {
209                final int[] rowNo = getParameterRows();         // 4.0.0 (2005/01/31)
210                final int selcount = rowNo.length;      // 4.0.0 (2005/01/31)
211
212                final String[] key = (String[])StringUtil.enume2Array( getParameterNames(), new String[0] );
213                String[] dbkey = null;
214
215                int dbcount = 0;
216
217                int recount = 0;
218                for( int i=0; i<key.length; i++ ) {
219                        if( isNormalRequestKey( key[i] ) ) {    // 3.4.0.3 (2003/09/10)
220                                recount++;
221                        }
222                }
223
224                if( keys != null && dbTable && selcount > 0 ) {
225                        dbkey = StringUtil.csv2Array( keys );
226                        dbcount = dbkey.length;
227                }
228
229                String[] val  = new String[ recount + dbcount + selcount ];
230                String[] keyt = new String[ recount + dbcount + selcount ];
231
232                int j = 0;
233                for( int i=0; i<key.length; i++ ) {
234                        if( isNormalRequestKey( key[i] ) ) {    // 3.4.0.3 (2003/09/10)
235                                keyt[j] = key[i];
236                                val[j]  = getRequestValue( key[i] );
237                                j++;
238                        }
239                }
240
241                if( dbTable && dbcount > 0 ) {
242                        table = (DBTableModel)getSessionAttribute( tableId );
243                        if( table != null ) {
244                                for( int i=0; i<dbcount; i++ ) {
245                                        keyt[recount + i] = dbkey[i];
246                                        val[recount +i]  = table.getValue(rowNo[0],table.getColumnNo( dbkey[i] ));
247                                }
248                        }
249                }
250
251                // 4.0.0 (2005/01/31) selected文字配列をrowNo数字配列に変更
252                for( int i=0; i<selcount; i++ ) {
253                        keyt[recount + dbcount + i] = HybsSystem.ROW_SEL_KEY;
254                        val[recount + dbcount + i]      = String.valueOf( rowNo[i] );
255                }
256
257//              return XHTMLTag.urlEncode( keyt,val );
258                return XHTMLTag.urlEncode( keyt,val,"&",useForceEnc ); // 5.10.15.3 (2019/09/27)
259        }
260
261        /**
262         * 【HTML】フレームに表示するソースファイルを指定します。
263         *
264         * @og.tag フレームに表示するソースファイルを指定します。
265         *
266         * @param       src ソースファイル
267         */
268        public void setSrc( final String src ) {
269                set( "src",getRequestParameter( src ) );
270        }
271
272        /**
273         * 【HTML】フレーム名を指定します(例:QUERY,RESULT,CONTENTS など)。
274         *
275         * @og.tag フレーム名を指定します。
276         *
277         * @param       name フレーム名
278         */
279        public void setName( final String name ) {
280                set( "name",getRequestParameter( name ) );
281        }
282
283        /**
284         * 【HTML】フレームに関する詳しい説明のあるURL(lobgdesc)を指定します。
285         *
286         * @og.tag lobgdescを指定します。
287         *
288         * @param       longdesc 詳しい説明のあるURL
289         */
290        public void setLongdesc( final String longdesc ) {
291                set( "longdesc",getRequestParameter( longdesc ) );
292        }
293
294        /**
295         * 【TAG】valsの値が[で開始している場合でもURLEncodeを通すかを設定します(初期値:false)。
296         * 
297         * @og.tag
298         * テーブルモデルの値の変換のため、通常は先頭が[の場合はエンコードがかかりません。
299         * 強制的にかける場合にtrueにします。
300         * 
301         * @og.rev 5.10.15.3 (2019/09/27) forceEnc追加
302         * 
303         * @param flg URLEncodeを通す場合は、trueをセット
304         */
305        public void setForceEnc( final String flg ) {
306                useForceEnc = nval( getRequestParameter( flg ), useForceEnc );
307        }
308
309//      /**
310//       * 【廃止】フレームの左右余白サイズ(marginwidth)を指定します。
311//       *  HTML5では廃止されている属性のため、可能であればCSSを利用してください。
312//       *
313//       * @og.tag フレームの左右余白サイズを指定します。
314//       *
315//       * @og.rev 6.9.5.0 (2018/04/23) 値の設定を行いません。
316//       * @og.rev 7.0.1.0 (2018/10/15) 廃止:物理削除
317//       *
318//       * @param       marginwidth 左右余白サイズ
319//       */
320//      public void setMarginwidth( final String marginwidth ) {
321////            set( "marginwidth",getRequestParameter( marginwidth ) );
322//      }
323
324//      /**
325//       * 【廃止】フレームの上下余白サイズ(marginheight)を指定します。
326//       *  HTML5では廃止されている属性のため、可能であればCSSを利用してください。
327//       *
328//       * @og.tag フレームの上下余白サイズを指定します。
329//       *
330//       * @og.rev 6.9.5.0 (2018/04/23) 値の設定を行いません。
331//       * @og.rev 7.0.1.0 (2018/10/15) 廃止:物理削除
332//       *
333//       * @param       marginheight 上下余白サイズ
334//       */
335//      public void setMarginheight( final String marginheight ) {
336////            set( "marginheight",getRequestParameter( marginheight ) );
337//      }
338
339//      /**
340//       * 【廃止】フレームサイズを変更できないよう(noresize)に指定します。
341//       *  HTML5では廃止されている属性のため、可能であればCSSを利用してください。
342//       *
343//       * @og.tag
344//       * フレームサイズを変更させない場合は、"noresize" を指定します。
345//       * 処理自体は、空文字列以外であれば、内部的に"noresize" を設定します。
346//       *
347//       * @og.rev 6.9.5.0 (2018/04/23) 物理削除
348//       *
349//       * @param       noresize フレームサイズ変更不可指定
350//       */
351//      public void setNoresize( final String noresize ) {
352//              final String ns = getRequestParameter( noresize );
353//              if( ns != null ) { set( "noresize", "noresize" ); }
354//      }
355
356//      /**
357//       * 【廃止】スクロールバー(scrolling)の表示/非表示[auto/yes/no]を指定します(初期値:auto)。
358//       *  HTML5では廃止されている属性のため、可能であればCSSを利用してください。
359//       *
360//       * @og.tag
361//       * auto:必要に応じてスクロールバーを表示(初期値)
362//       * yes:常にスクロールバーを表示
363//       * no:常にスクロールバーを表示しない
364//       *
365//       * @og.rev 6.9.5.0 (2018/04/23) 値の設定を行いません。
366//       * @og.rev 7.0.1.0 (2018/10/15) 廃止:物理削除
367//       *
368//       * @param       scrolling  スクロールバーの表示方法指定 [auto:自動/yes:常時表示/no:非表示]
369//       */
370//      public void setScrolling( final String scrolling ) {
371////            set( "scrolling",getRequestParameter( scrolling ) );
372//      }
373
374//      /**
375//       * 【廃止】フレームの境界線(frameborder)の[0:非表示/1:表示]を指定します(初期値:1)。
376//       *  HTML5では廃止されている属性のため、可能であればCSSを利用してください。
377//       *
378//       * @og.tag
379//       * 0:枠を表示しない
380//       * 1:枠を表示する。
381//       * 初期値は、1:枠を表示する です。
382//       *
383//       * @og.rev 6.9.5.0 (2018/04/23) 物理削除
384//       *
385//       * @param       frameborder     フレームの境界線 [0:枠非表示/1:枠表示]
386//       */
387//      public void setFrameborder( final String frameborder ) {
388//              set( "frameborder",getRequestParameter( frameborder ) );
389//      }
390
391        /**
392         * 【TAG】ソース指定の画面を変更します。
393         *
394         * @og.tag
395         * src 指定がデフォルト設定で、changeGamen属性が設定されている
396         * 場合には、この値が優先されます。
397         * changeGamen は、画面IDのみ指定してください。src には、このID+"/index.jsp" が
398         * 追加されます。つまり、changeGamen="{&#064;GAMENID}" という指定をしておけば、
399         * FavoriteLinkTag 等で引数に GAMENID が指定された場合のみ、この属性が有効になり、
400         * src="実画面ID/index.jsp" が指定されたことと同じ結果になります。
401         *
402         * @og.rev 3.1.2.0 (2003/04/07) 画面IDと実画面ディレクトリとの関連見直し(DIRの代りにGAMENIDを推奨)
403         * @og.rev 4.2.1.1 (2008/04/30) 画面切り替えをするのは、アドレスが設定されいる場合に限る
404         * @param       src     置換えソース
405         */
406        public void setChangeGamen( final String src ) {
407                final String sc = nval( getRequestParameter( src ),changeGmn );
408                if( sc != null ) {
409                        final GUIInfo guiInfo = getGUIInfo( sc );
410                        if( guiInfo != null && guiInfo.getAddress() != null && guiInfo.getAddress().length() > 0 ) { // 見つからない場合は、アクセス不可
411                                changeGmn = guiInfo.getRealAddress( "index.jsp" );
412                        }
413                }
414        }
415
416        /**
417         * 【TAG】引数を指定します。
418         *
419         * @og.tag
420         * URL の引数にセットするキーを CSV形式でセットします。
421         *
422         * @param       key 引数
423         */
424        public void setKeys( final String key ) {
425                keys = getRequestParameter( key ) ;
426        }
427
428        /**
429         * 【TAG】前ページで選択したデータ列の情報を次のページに渡すかどうか[true:渡す/false:渡さない]を指定します(初期値:false)。
430         *
431         * @og.tag
432         * ただし、1行分のデータのみです。(複数選択時は、最初の1件目)
433         * trueを指定すると、データを渡します。falseの場合は、渡しません。
434         * 初期値は、false:渡さない です。
435         *
436         * @param       db 選択データを渡すかどうか [true:渡す/false:渡さない]
437         */
438        public void setDbTable( final String db ) {
439                dbTable = nval( getRequestParameter( db ),dbTable );
440        }
441
442        /**
443         * 標準的な リクエスト情報かどうかを判断します。
444         *
445         * これは、引数のキーが、HybsSystem.ROW_SEL_KEY か、
446         * DBTableModel で送信されたキー( キー__番号)形式の場合は
447         * false を返します。
448         * 通常のリクエストキーとして扱いたくない場合の判定に使用します。
449         *
450         * @og.rev 3.4.0.3 (2003/09/10) 新規追加
451         * @og.rev 3.5.2.0 (2003/10/20) システムパラメータ の FRAME_UNDER_BAR_REQUEST_KEY_USED を使用。
452         * @og.rev 3.5.5.0 (2004/03/12) 名前と行番号の区切り記号("__")を、HybsSystem.JOINT_STRING  に変更。
453         * @og.rev 6.8.1.1 (2017/07/22) 転送不要のキーを除外します。
454         *
455         * @param key 判定するキー
456         *
457         * @return 標準的な リクエスト情報かどうか [true:標準的/false:それ以外]
458         */
459        private boolean isNormalRequestKey( final String key ) {
460                return  key != null &&
461                                ! key.equals(     HybsSystem.ROW_SEL_KEY  ) &&
462                                ! key.startsWith( HybsSystem.NO_XFER_KEY  ) &&                          // 6.8.1.1 (2017/07/22)
463                                ( key.indexOf(    HybsSystem.JOINT_STRING ) < 0 || UNDER_BAR_KEY_USED ) ;
464        }
465
466        /**
467         * このオブジェクトの文字列表現を返します。
468         * 基本的にデバッグ目的に使用します。
469         *
470         * @return このクラスの文字列表現
471         * @og.rtnNotNull
472         */
473        @Override
474        public String toString() {
475                return ToString.title( this.getClass().getName() )
476                                .println( "VERSION"             ,VERSION        )
477                                .println( "tableId"             ,tableId        )
478                                .println( "changeGmn"   ,changeGmn      )
479                                .println( "keys"                ,keys           )
480                                .println( "dbTable"     ,dbTable        )
481                                .println( "Other..."    ,getAttributes().getAttribute() )
482                                .fixForm().toString() ;
483        }
484}