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 static org.opengion.fukurou.util.StringUtil.nval;
019
020import java.util.List;
021import java.util.ArrayList;
022import java.util.Map;
023import java.util.LinkedHashMap;
024import java.util.Collections;
025import java.util.Locale ;                                                               // 6.7.6.1 (2017/03/17)
026import java.util.concurrent.ConcurrentMap;                              // 6.7.8.0 (2017/04/21)
027import java.util.concurrent.ConcurrentHashMap;                  // 6.7.8.0 (2017/04/21)
028
029import org.opengion.hayabusa.common.HybsSystem;
030import org.opengion.hayabusa.db.DBTableModel;
031import org.opengion.fukurou.util.ToString;                              // 6.8.5.0 (2018/01/09)
032
033import static org.opengion.hayabusa.taglib.ValueMapParamTag.VMP_KEYS;   // 6.7.8.0 (2017/04/21)
034
035/**
036 * DBTableModelオブジェクトから、指定のキー情報と、レコードから、Mapオブジェクトを作成し、それを、
037 * BODY部のフォーマットに対応して、出力します。
038 *
039 * valueタグの、command="MAPOBJ" や、ALL_MAPOBJ に相当する処理を、複数キーと行レベルのデータで
040 * 管理します。
041 *
042 * 設定した値は、Mapを優先した、特殊な、{@XXXX} 形式で 取り出すことができます。
043 *
044 * keys で、CSV形式でカラム名を指定し、これらを、連結した文字列を、Mapのキー情報に使います。
045 * Mapの値情報は、そのレコードの配列になります。
046 * keys を指定しない場合は、最初のカラムの値が、キーになります。
047 * キーが重複する場合、先に現れたデータが優先されます。
048 *
049 * 値の取出し方法は、キーに対して、{@XXXX} 形式を、適用します。
050 * Map に存在しないキーは、リクエスト変数や、通常のvalus変数を見ます。
051 * valClm で、{@XXXX} 形式で取り出す値のカラムを指定できます。
052 * valClm を指定しない場合は、2番目のカラムを使用します。
053 * 
054 * 特殊機能
055 *   ・holdTag属性:{@XXXX} を、指定のタグで囲います。
056 *     例えば、holdTag="span" とすると、<span class="YYYYの値" >XXXXの値</span>
057 *     という文字列を作成します。
058 *   ・clsClms属性:先の指定のタグで囲う場合、そのタグのclass属性を指定できます。
059 *     複数指定した場合は、スペースで、連結します。
060 *   ・{@XXXX cls="B"} とすると、個別の clsClms の値を使用せず、この値を、class属性として使います。
061 *     clsClms と同様に、holsTag属性を指定しておく必要があります。
062 *   ・tipsClms属性:先の指定のタグで囲う場合、そのタグのtitle属性を指定できます。
063 *     マウスオーバーで、チップス表示されます。
064 *   ・{@XXXX tips="YYYY"} とすると、個別の tipsClms の値を使用せず、この値を、title属性として使います。
065 *     tipsClms と同様に、holsTag属性を指定しておく必要があります。
066 *   ・nnClms属性:この属性で指定された値が、nullの場合、{@XXXX} の解析を行いません。
067 *     正確に言うと、Mapに取り込みません。この場合、先のholdTag属性で指定したタグそのものも
068 *     出力しません。
069 *   ・{@XXXX* str="val"} とすると、キーワードのあいまい検索部分に、strで指定した
070 *     val文字列が存在する場合のみ有効とします。
071 *   ・キーに対して、Mapは、行データ全部を持っています。{@XXXX} は、最初のカラムの値です。
072 *   ・2番目を取得する場合は、{@XXXX 1}と、3番目は、{@XXXX 2}と指定します。
073 *   ・{@XXXX*} を指定すると、キーのあいまい検索で、キーそのものを複数選択することが出来ます。
074 *     この場合、spanタグで囲う機能と併用すると、複数のspanタグを持つ文字列を合成できます。
075 *     この特定のタグは、holdTag 属性で指定します。
076 *     このキーのあいまい検索で、表示する順番は、DBTableModelでMapに読み込んだ順番になります。
077 *     {@XXXX* 2} のような、取得カラムの指定も可能です。
078 *     取得カラムの指定も可能ですが、カラム番号は、常に一番最後に記述してください。
079 *   ・{@XXXX!*} とすると、表示する順番を、逆順にすることが出来ます。取得カラムの指定も可能です。
080 *   ・{@$XXXX} とすると、holdTagも、clsClms も使用せず、設定値のみ出力します。
081 *     この場合は、固定値になるため、holsTagも、clsClms も使用しません。
082 *   ・{@*XXXX!*} とすると、キーのあいまい指定の残り部分の文字列を出力します。連番の場合の番号を取り出せます。
083 *   ・{@^XXXX} とすると、request.getAttribute()の値を優先して使用します。{@^XXXX*}などのあいまい指定も可能です。
084 *     この場合、オリジナルのキーは、DBTableModel上に必要です。値の入れ替えのみ、行う感じです。
085 *
086 * ※ このタグは、Transaction タグの対象です。
087 *
088 * @og.formSample
089 * ●形式:<og:valueMap />
090 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を特殊な方法で解析します)
091 *
092 * ●Tag定義:
093 *   <og:valueMap
094 *       keys               【TAG】パラメータから取り出すキーとなるカラム名を、CSV形式で指定します(初期値:最初のカラム)
095 *       valClm             【TAG】パラメータから取り出す値のカラム名を指定します(初期値:2番目のカラム)
096 *       holdTag            【TAG】値の前後を、指定のタグで挟みます
097 *       clsClms            【TAG】holdTagを使用するとき、そのタグの属性にclass属性を出力する場合のカラム名をCSV形式で指定します
098 *       tipsClms           【TAG】holdTagを使用するとき、そのタグの属性にtitle属性を出力する場合のカラム名をCSV形式で指定します
099 *       nnClms             【TAG】パラメータが NULL の時に、設定しないカラム名を、CSV形式で指定します
100 *       reqAttUpClms       【TAG】{@^XXXX}使用時に request.getAttribute() をセットすると同時に設定するカラム名をCSV形式で指定します 6.9.2.0 (2018/03/05)
101 *       selectedAll        【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:true)
102 *       separator          【TAG】キーとなるカラム名の値を連結する項目区切り文字をセットします(初期値:"_")
103 *       tableId            【TAG】sessionから取得する DBTableModelオブジェクトの ID(初期値:HybsSystem.TBL_MDL_KEY)
104 *       scope              【TAG】DBTableModelオブジェクトを取得する場合の、scope(初期値:session)
105 *       xssCheck           【TAG】パラメータの HTMLTag開始/終了文字(><) 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_XSS_CHECK[=true])
106 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
107 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
108 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
109 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
110 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
111 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
112 *   >   ... Body ...
113 *   </og:valueMap>
114 *
115 * ●使用例
116 * <og:query command="{@command}" debug="{@debug}" maxRowCount="{@maxRowCount}">
117 *         select CLM,NAME_JA,LABEL_NAME,KBSAKU,SYSTEM_ID,LANG,
118 *                 FGJ,USRSET,DYSET,USRUPD,DYUPD
119 *         from GF41
120 *     <og:where>
121 *         <og:and value = "SYSTEM_ID  =  '{@SYSTEM_ID}'"  />
122 *         <og:and value = "LANG       =  '{@LANG}'"       />
123 *         <og:and value = "CLM        like '{@CLM}'"      />
124 *         <og:and value = "NAME_JA    like '{@NAME_JA}'"  />
125 *         <og:and value = "LABEL_NAME like '{@LABEL_NAME}'" />
126 *         <og:and value = "KBSAKU     =    '{@KBSAKU}'"   />
127 *     </og:where>
128 *     <og:appear startKey = "order by" value = "{@ORDER_BY}"
129 *                 defaultVal = "SYSTEM_ID,CLM,LANG" />
130 * </og:query>
131 *
132 * <og:valueMap keys="SYSTEM_ID,CLM" holdTag="div" separator="_" clsClms="LANG,FGJ" >
133 * {@XX_AA0001} <br />   SYSTEM_IDとCLMの値を、separatorで連結。値は、キーの次(LABEL_NAME)
134 * {@XX_AA0001 1} <br /> 行番号の2番目(上のSQLではNAME_JA)の値
135 * {@XX_AA0001 2} <br /> 行番号の3番目(上のSQLではLABEL_NAME)の値
136 * 
137 * {@XX_AA001* 2} <br /> キーの前方一致する行の3番目の値
138 * 
139 * {@XX_AA000!* 1} キーの前方一致する行の2番目の値を、逆順で表示
140 * 
141 * </og:valueMap>
142 *
143 *  ・ キーは、select文の1番目のカラム
144 *     <og:og:valueMap >  ・・・フォーマット・・・ </og:valueMap>
145 *  ・ キーが複数で、ユニークになる。(keys)
146 *     <og:og:valueMap keys="SYSTEM_ID,CLM" >  ・・・フォーマット・・・ </og:valueMap>
147 *  ・ 値をdivタグで囲う。(holdTag)
148 *     <og:og:valueMap keys="SYSTEM_ID,CLM" holdTag="div" >  ・・・フォーマット・・・ </og:valueMap>
149 *  ・ キーの連結のセパレータを指定。(separator)
150 *     <og:og:valueMap keys="SYSTEM_ID,CLM" holdTag="div" separator="_" >  ・・・フォーマット・・・ </og:valueMap>
151 *  ・ 値をdivタグで囲う時に、クラス属性を追加します。(clsClms)
152 *     <og:og:valueMap keys="SYSTEM_ID,CLM" holdTag="div" separator="_" clsClms="LANG,FGJ" >  ・・・フォーマット・・・ </og:valueMap>
153 *  ・ 値をdivタグで囲う時に、チップス表示(title属性)を追加します。(tipsClms)
154 *     <og:og:valueMap keys="SYSTEM_ID,CLM" holdTag="div" separator="_" clsClms="LANG,FGJ" tipsClms="NAME_JA,LABEL_NAME" >  ・・・フォーマット・・・ </og:valueMap>
155 *
156 * @og.group その他部品
157 * @og.rev 6.7.1.0 (2017/01/05) 新規作成
158 *
159 * @version  6.7
160 * @author   Kazuhiko Hasegawa
161 * @since    JDK8.0,
162 */
163public class ValueMapTag extends CommonTagSupport {
164        /** このプログラムのVERSION文字列を設定します。   {@value} */
165        private static final String VERSION = "6.9.2.0 (2018/03/05)" ;
166        private static final long serialVersionUID = 692020180305L ;
167
168        private static final String CLS_KEY  = "cls=" ;         // 6.7.3.0 (2017/01/27) cls指定のキーワード
169        private static final String TIPS_KEY = "tips=" ;        // 6.7.3.0 (2017/01/27) tips指定のキーワード
170        private static final String STR_KEY  = "str=" ;         // 6.8.0.1 (2017/06/30) str指定のキーワード
171
172        private static final String NONE1       = "<style type=\"text/css\">." ;        // 6.7.8.0 (2017/04/21)
173        private static final String NONE2       = " { display : none ;} </style>" ;     // 6.7.8.0 (2017/04/21)
174
175        private DBTableModel table              ;
176
177        private String          tableId         = HybsSystem.TBL_MDL_KEY;
178        private boolean         selectedAll     = true;
179        private String          keys            ;
180        private String          valClm          ;                               // 6.7.2.0 (2017/01/16)
181        private String          nnClms          ;                               // このカラムの値が、nullのレコードは、使用しません。
182        private String          holdTag         ;                               // nullの場合は、なにもはさまない。
183        private String          clsClms         ;                               // holdTagで指定したタグの属性に、class属性を追加します。
184        private String          tipsClms        ;                               // 6.7.3.0 (2017/01/27) holdTagで指定したタグの属性に、title属性を追加します。
185        private String          reqAttUpClms;                           // 6.9.2.0 (2018/03/05) request.getAttribute() をセットすると同時に設定するカラム名
186        private String[]        reqAttClms      ;                               // 6.9.2.0 (2018/03/05) reqAttUpClms を、配列に分解したもの
187        private String          scope           = "session";    // "request","session"
188        private String          separator       = "_";                  // 項目区切り文字
189        private boolean         xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" ); // 5.1.7.0 (2010/06/01) XSS対策
190
191        private int[]           clsClmsNo       ;                               // clsClmsが指定されない場合は、長さゼロの配列
192        private int[]           tipsClmsNo      ;                               // 6.7.3.0 (2017/01/27) tipsClmsが指定されない場合は、長さゼロの配列
193        private int[]           reqAttClmsNo;                           // 6.9.2.0 (2018/03/05) reqAttUpClmsが指定されない場合は、長さゼロの配列
194        private int                     valClmNo        = 1;                    // valClmが指定されない場合は、2番目のカラム(=1)の値を使用します。
195
196        private String          body            ;                               // パラメータ処理済みのBODY部分の文字列
197        private String          restChangeKey   ;                       // ValueMapParamTag で置き換え処理を行うキーワード
198        private boolean         useNoneClsKey   ;                       // mapObj の残り処理をおこなうかどうか(true:行う)
199
200        // synchronizedMap にする必要性があるのか無いのか、よく判っていません。
201        /** Collections.synchronizedMap で、同期します。テーブルの行の取得順に、Mapに追加していきます。(先に登録したデータが有効) */
202        private final Map<String,String[]> mapObj = Collections.synchronizedMap( new LinkedHashMap<>() );
203
204        // ValueMapParamTagから受け取った、各種設定情報を、管理するMapオブジェクト。
205        private final ConcurrentMap<VMP_KEYS,String> paramMap = new ConcurrentHashMap<>();
206
207        // ValueMapParamTag で使用する、未使用のキーワードを管理するMap
208        /** Collections.synchronizedMap で、同期します。テーブルの行の取得順に、Mapに追加していきます。(先に登録したデータが有効) */
209        private final Map<String,String[]> restMap = Collections.synchronizedMap( new LinkedHashMap<>() );
210
211        /**
212         * デフォルトコンストラクター
213         *
214         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
215         *
216         */
217        public ValueMapTag() { super(); }               // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
218
219        /**
220         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
221         *
222         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
223         *
224         * @return      後続処理の指示
225         */
226        @Override
227        public int doStartTag() {
228                if( useTag() ) {
229                        useXssCheck( xssCheck );
230                        table = (DBTableModel)getObject( tableId );
231                        if( table != null && table.getRowCount() > 0 && table.getColumnCount() > 0 ) {
232                                makeMapObj( table );            // Body の評価前にMapを作成する必要がある。
233
234                                return EVAL_BODY_BUFFERED ;     // Body を評価する
235                        }
236                }
237                return SKIP_BODY ;                                      // Body を評価しない
238        }
239
240        /**
241         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
242         *
243         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
244         *
245         * @return      後続処理の指示(SKIP_BODY)
246         */
247        @Override
248        public int doAfterBody() {
249                body = getBodyString();
250
251                return SKIP_BODY ;
252        }
253
254        /**
255         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
256         *
257         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
258         *
259         * @return      後続処理の指示
260         */
261        @Override
262        public int doEndTag() {
263                debugPrint();           // 4.0.0 (2005/02/28)
264                if( useTag() && body != null ) {
265                        jspPrint( body );
266                }
267
268                // mapObj の残り処理が必要かどうか。mapObj が空で、NONE_CLS_KEY が存在する場合は、残を隠す。
269                if( useNoneClsKey ) {
270                        final String noneClassKey = paramMap.get( VMP_KEYS.NONE_CLS_KEY );
271                        jspPrint( NONE1 + noneClassKey + NONE2 );
272                }
273
274                return EVAL_PAGE ;
275        }
276
277        /**
278         * タグリブオブジェクトをリリースします。
279         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
280         *
281         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
282         * @og.rev 6.7.2.0 (2017/01/16) valClm 追加
283         * @og.rev 6.7.3.0 (2017/01/27) tipsClms 追加
284         * @og.rev 6.7.8.0 (2017/04/21) valueMapParam関連
285         * @og.rev 6.9.2.0 (2018/03/05) reqAttUpClms 追加
286         */
287        @Override
288        protected void release2() {
289                super.release2();
290                table           = null;
291                tableId         = HybsSystem.TBL_MDL_KEY;
292                selectedAll     = true;
293                keys            = null;
294                valClm          = null;                 // 6.7.2.0 (2017/01/16) 新規作成
295                nnClms          = null;                 // 6.7.2.0 (2017/01/16) 名称変更
296                holdTag         = null;
297                clsClms         = null;                 // 6.7.3.0 (2017/01/27) 追加
298                tipsClms        = null;                 // 6.7.2.0 (2017/01/16) 名称変更
299                reqAttUpClms= null;                     // 6.9.2.0 (2018/03/05) request.getAttribute() をセットすると同時に設定するカラム名
300                reqAttClms      = null;                 // 6.9.2.0 (2018/03/05) reqAttUpClms を、配列に分解したもの
301                scope           = "session";    // DBTableModel の取得先のscope
302                separator       = "_";
303                xssCheck        = HybsSystem.sysBool( "USE_XSS_CHECK" );        // 5.1.7.0 (2010/06/01) XSS解除対応
304                body            = null;
305                mapObj.clear();
306
307                clsClmsNo       = null;                 // clsClmsが指定されない場合は、長さゼロの配列
308                tipsClmsNo      = null;                 // 6.7.3.0 (2017/01/27) tipsClmsが指定されない場合は、長さゼロの配列
309                reqAttClmsNo= null;                     // 6.9.2.0 (2018/03/05) reqAttUpClmsが指定されない場合は、長さゼロの配列
310                valClmNo        = 1;                    // valClmが指定されない場合は、2番目のカラム(=1)の値を使用します。
311
312                paramMap.clear();                       // 6.7.8.0 (2017/04/21) valueMapParam関連
313                restMap.clear();                        // 6.7.8.0 (2017/04/21) valueMapParam関連
314                restChangeKey   = null ;        // ValueMapParamTag で置き換え処理を行うキーワード
315                useNoneClsKey   = false ;       // mapObj の残り処理をおこなうかどうか(true:行う)
316        }
317
318        /**
319         * 指定のスコープの内部キャッシュ情報に、DBTableModel の選択された値を登録します。
320         *
321         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
322         * @og.rev 6.7.2.0 (2017/01/16) valClm 追加
323         * @og.rev 6.7.3.0 (2017/01/27) tipsClms 追加
324         * @og.rev 6.7.8.0 (2017/04/21) valueMapParam関連
325         * @og.rev 6.9.2.0 (2018/03/05) reqAttUpClms 追加
326         *
327         * @param table         DBTableModelオブジェクト
328         */
329        private void makeMapObj( final DBTableModel table ) {
330                final int[] rowNo = getParameterRows();
331                if( rowNo.length == 0 ) { return; }
332
333                final int[] keysNo              = getClmNos( table,keys    , 0 );               // keysが指定されない場合は、先頭カラムを使用します。
334                final int[] nnClmsNo    = getClmNos( table,nnClms  ,-1 );               // nnClmsが指定されない場合は、長さゼロの配列
335                                        clsClmsNo       = getClmNos( table,clsClms ,-1 );               // clsClmsが指定されない場合は、長さゼロの配列
336                                        tipsClmsNo      = getClmNos( table,tipsClms,-1 );               // tipsClmsが指定されない場合は、長さゼロの配列
337                                        reqAttClmsNo= getClmNos( table,reqAttUpClms,-1 );       // 6.9.2.0 (2018/03/05) reqAttClmsが指定されない場合は、長さゼロの配列
338
339                if( reqAttUpClms != null && !reqAttUpClms.isEmpty() ) {                 // 6.9.2.0 (2018/03/05) reqAttUpClms を、配列に分解したもの
340                        reqAttClms = reqAttUpClms.split( "," );
341                }
342
343                for( int j=0; j<rowNo.length; j++ ) {
344                        final String[] rowData = table.getValues( j );
345
346                        // まず、nullチェックして、対象行かどうかを判定する。
347                        if( isNotNullCheck( rowData , nnClmsNo ) ) {
348                                // Map に登録するキーを連結して作成します。
349                                final String mapkey = getAppendKeys( rowData , keysNo , separator );
350                                mapObj.computeIfAbsent( mapkey, k -> rowData );         // まだ値に関連付けられていない場合、追加します。(先に登録したデータが有効)
351                //              mapObj.put( mapkey, rowData );                                          // 後で登録したデータが、有効になります。
352                        }
353                }
354                restMap.putAll( mapObj );               // 6.7.8.0 (2017/04/21) 一旦、すべてのMapをコピーします。
355
356                // valClmが指定されない場合は、2番目のカラム(=1)の値を使用します。
357                valClmNo = valClm == null || valClm.isEmpty() ? 1 : table.getColumnNo( valClm.trim() ); // 存在しない場合は、Exception
358        }
359
360        /**
361         * カラム名のCSV文字列を、DBTableModel の列番号の配列に変換します。
362         *
363         * カラム名のCSV文字列が、無指定の場合、no で指定するカラム番号を
364         * デフォルトとして使用します。no が、マイナスの場合は、長さゼロの
365         * 配列を返します。
366         *
367         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
368         * @og.rev 6.7.2.0 (2017/01/16) カラム番号の取り方を変更
369         *
370         * @param       table           DBTableModelオブジェクト
371         * @param       clms            カラム名のCSV文字列( nullではない )
372         * @param       no                      clmsが、nullか、空文字の場合の、カラム番号
373         * @return      カラム名の列番号の配列
374         */
375        private int[] getClmNos( final DBTableModel table , final String clms , final int no ) {
376                final int[] clmNo ;
377                if( clms == null || clms.isEmpty() ) {
378                        if( no < 0 ) { clmNo = new int[0]; }                    // 長さゼロの配列
379                        else         { clmNo = new int[] { no }; }              // 指定のカラム番号を持つ配列。
380                }
381                else {
382                        final String[] clmAry = clms.split( "," );
383                        clmNo = new int[clmAry.length];
384                        for( int i=0; i<clmAry.length; i++ ) {
385                                clmNo[i] = table.getColumnNo( clmAry[i].trim() );       // 存在しない場合は、Exception
386                        }
387                }
388
389                return clmNo;
390        }
391
392        /**
393         * 指定のカラムの値のすべてが、nullか、空文字列でない場合は、true を返します。
394         *
395         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
396         *
397         * @param       rowData 行データ
398         * @param       clmNo   カラム番号配列
399         * @return      nullか、空文字列でない場合は、true
400         */
401        private boolean isNotNullCheck( final String[] rowData , final int[] clmNo ) {
402                boolean rtn = true;                                             // カラムがない場合は、true になります。
403
404                for( int i=0; i<clmNo.length; i++ ) {
405                        final String val = rowData[ clmNo[i] ];
406                        if( val == null || val.isEmpty() ) {
407                                rtn = false;
408                                break;
409                        }
410                }
411                return rtn;
412        }
413
414        /**
415         * Mapのキーとなるキーカラムの値を連結した値を返します。
416         *
417         * @param       rowData 行データ
418         * @param       clmNo   カラム番号配列
419         * @param       sep             結合させる文字列
420         *
421         * @return      Mapのキーとなるキーカラムの値を連結した値
422         * @og.rtnNotNull
423         */
424        private String getAppendKeys( final String[] rowData , final int[] clmNo , final String sep ) {
425                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
426
427                if( clmNo.length > 0 ) {
428                        buf.append( rowData[ clmNo[0] ] );                              // 最初のひとつ目
429                        for( int i=1; i<clmNo.length; i++ ) {
430                                final String val = rowData[ clmNo[i] ];
431                                if( val != null && !val.isEmpty() ) {
432                                        buf.append( sep ).append( val );
433                                }
434                        }
435                }
436                return buf.toString().trim();
437        }
438
439        /**
440         * Mapの値となる値カラムに対応する文字列配列を返します。
441         *
442         * ここでは、行データに対して、配列の添え字(カラム番号)を元に、値を求めます。
443         * その際、holdTag や、clsClms で指定したクラス名などの付加情報もセットします。
444         * さらに、{&#064;$XXXX} などの、holdTagの抑止(生データを返す) 処理を行います。
445         *
446         * @param       rowData         行の配列データ
447         * @param       val                     値データ
448         * @param       isNormal        holdTagを使用せず、ノーマル状態の値を出力するかどうか[true:ノーマルの値]
449         * @param       cls                     clsClmsNoの使用を抑止し、指定の値を、class属性にセットします。(nullはclsClmsNoを使用、isEmpty() は、classの削除、それ以外は置き換え)
450         * @param       tips            tipsClmsNoの使用を抑止し、指定の値を、title属性にセットします。(nullはtipsClmsNoを使用、isEmpty() は、titleの削除、それ以外は置き換え)
451         * @param       sufix           キーのあいまい指定時に、あいまいキー以降の文字列を指定します。あれば、その値を使用します。
452         *
453         * @og.rev 6.7.3.0 (2017/01/27) tips 追加
454         *
455         * @return      Mapのキーに対応する修飾した値
456         * @og.rtnNotNull
457         */
458        private String getMapVals( final String[] rowData , final String val , final boolean isNormal , final String cls , final String tips , final String sufix ) {
459                String rtnVal = sufix == null || sufix.isEmpty() ? val : sufix ;
460
461                if( !isNormal && holdTag != null && !holdTag.isEmpty() ) {
462                        // 毎行ごとに、class属性の値は異なる。
463                        final String clazz = cls  == null ? getAppendKeys( rowData,clsClmsNo ," " ) : cls ;             // class 属性は、スペースで連結
464                        final String title = tips == null ? getAppendKeys( rowData,tipsClmsNo," " ) : tips ;    // title 属性は、スペースで連結
465
466                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
467                        buf.append( '<' ).append( holdTag );
468                        if( !clazz.isEmpty() ) { buf.append( " class=\"" ).append( clazz ).append( '"' ); }
469                        if( !title.isEmpty() ) { buf.append( " title=\"" ).append( title ).append( '"' ); }
470                        buf.append( '>' ).append( rtnVal ).append( "</" ).append( holdTag ).append( '>' );
471
472                        rtnVal = buf.toString();
473                }
474                return rtnVal ;
475        }
476
477        /**
478         * リクエスト情報の文字列を取得します。
479         *
480         * これは、CommonTagSupportの#getRequestValue( String ) を
481         * オーバーライドして、Mapから、設定値を取得します。
482         *
483         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
484         * @og.rev 6.7.2.0 (2017/01/16) valClm 追加
485         * @og.rev 6.7.3.0 (2017/01/27) tips 追加
486         * @og.rev 6.7.6.1 (2017/03/17) 値データを渡すようにします(isAttVal の追加対応)。
487         * @og.rev 6.7.8.0 (2017/04/21) valueMapParam関連
488         * @og.rev 6.8.0.1 (2017/06/30) str指定のキーワード
489         * @og.rev 6.9.2.0 (2018/03/05) reqAttUpClms 追加
490         *
491         * @param    key キー
492         *
493         * @return   リクエスト情報の文字列
494         * @see         CommonTagSupport#getRequestValue( String )
495         */
496        @Override
497        protected String getRequestValue( final String key ) {
498                if( key.equals( restChangeKey ) ) { return makeRestValue(); }           // 6.7.8.0 (2017/04/21)
499
500                // {@!XXXX} や、{@*XXXX!*} の場合のキー対応。最初に行う。
501                final char ch1 = key.charAt(0);
502                final boolean isNormal = ch1 == '$' ;           // holdTag を使わず、値そのものを出します。
503                final boolean isSufix  = ch1 == '*' ;           // あいまい検索時に、あいまいで削除された部分文字列を使うかどうか。
504                final boolean isAttVal = ch1 == '^' ;           // 値を、request.getAttribute()の値を優先して使用します。
505
506                final StringBuilder keyBuf = new StringBuilder( key.trim() );
507
508                if( isNormal || isSufix || isAttVal ) { keyBuf.deleteCharAt( 0 ); }             // 先頭の文字を削除
509
510                // カラム番号の取得のための分割。存在する場合は、必ず一番最後にします。
511                final int ad1  = keyBuf.lastIndexOf( " " );             // 後ろから検索して、スペースで分割
512                int       vcNo = valClmNo;
513                if( ad1 > 0 ) {
514                        // 必要かどうかはともかく、NumberFormatException で、判定すると、遅くなる気がする。
515                        final char ch = keyBuf.charAt( ad1 + 1 );       // 数字であろう先頭文字
516                        if( '0' <= ch && ch <= '9' ) {
517                                try {
518                                        vcNo   = Integer.parseInt( keyBuf.substring( ad1 + 1 ) );
519                                        keyBuf.setLength( ad1 );                                                                        // スペースが残っている可能性がある
520                                }
521                                catch( NumberFormatException ex ) {             // 数値変換失敗時は、普通のパラメータだった場合。
522        //                              vcNo   = valClmNo;              // vcNo は、セットする前にException が発生している。
523        //                              mapkey = key;                   // mapkey は、スペースも含むすべてのキーになる。・・・・・ NumberFormatException が先なので、setLength されていない。
524                                }
525                        }
526                }
527
528                // cls="B" 属性の取得
529                final String cls = getExtParam( keyBuf,CLS_KEY );               // 6.8.0.1 (2017/06/30) 関数化
530
531                // 6.7.3.0 (2017/01/27) tips="YYYY" 属性の取得
532                final String tips = getExtParam( keyBuf,TIPS_KEY );             // 6.8.0.1 (2017/06/30) 関数化
533
534                // 6.8.0.1 (2017/06/30) str指定のキーワード。先に取り除かないと、type 判定時の endsWith が効かない。
535                final String instr = getExtParam( keyBuf,STR_KEY );
536
537                // 中途半端に、スペースが残っていると厄介なので、削除しておきます。
538                final String mapkey = keyBuf.toString().trim();
539
540                // type==0 は、オリジナル。それ以外は、キーから取り除く文字数
541                final int type = mapkey.endsWith( "!*" ) ? 2 : mapkey.endsWith( "*" ) ? 1 : 0 ;
542
543                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
544                if( type == 0 ) {
545                        final String[] rowData = mapObj.get( mapkey );
546                        restMap.remove( mapkey );                                                       // 6.7.8.0 (2017/04/21) valueMapParam関連
547
548                        if( rowData != null && vcNo < rowData.length ) {
549                                // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
550                                // 6.9.2.0 (2018/03/05) DBTableModel への値のフィードバック
551//                              final String val = isAttVal ? nval( (String)getRequestAttribute( mapkey.toUpperCase(Locale.JAPAN) ) , rowData[vcNo] ) : rowData[vcNo] ;
552                                if( isAttVal ) {
553                                        // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
554                                        final String attVal = (String)getRequestAttribute( mapkey.toUpperCase(Locale.JAPAN) );
555                                        if( attVal != null && !attVal.isEmpty() ) {
556                                                rowData[vcNo] = attVal; // RequestAttribute をテーブルに戻す。
557                                                for( int i=0; i<reqAttClmsNo.length; i++ ) {    // 未設定の場合は、長さゼロの配列。
558                                                        if( reqAttClmsNo[i] >= 0 ) {
559                                                                final String reqAtt = (String)getRequestAttribute( reqAttClms[i] );
560                                                                rowData[reqAttClmsNo[i]] = reqAtt;              // 同時に戻すカラムの値
561                                                        }
562                                                }
563                                        }
564                                }
565
566                                final String val = rowData[vcNo] ;
567
568                                buf.append( getMapVals( rowData , val , isNormal , cls , tips , null ) );
569                        }
570                        else {
571                                buf.append( super.getRequestValue( key , xssCheck ) );                          // 添字も合わせて、上位に問い合わせる。
572                        }
573                }
574                else {
575                        final String subKey = mapkey.substring( 0,mapkey.length()-type );               // ほんとは、keyBuf で処理したかった。
576                        final List<String> list = new ArrayList<>();
577                        for( final Map.Entry<String,String[]> entry : mapObj.entrySet() ) {             // {@XXXX}を見つける都度、全Mapをスキャンしているので、非効率
578                                final String mapkey2 = entry.getKey();
579                                // 6.8.0.1 (2017/06/30) str指定のキーワード
580                                if( mapkey2.startsWith( subKey ) && ( instr == null || mapkey2.contains( instr ) ) ) {
581                                        final String[] rowData = entry.getValue();
582                                        if( rowData != null && vcNo < rowData.length ) {
583                                                final String sufix = isSufix ? mapkey2.substring( subKey.length() ) : null ;    // あいまいキーの残りの文字列
584                                                // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
585                                                // 6.9.2.0 (2018/03/05) DBTableModel への値のフィードバック
586//                                              final String val   = isAttVal ? nval( (String)getRequestAttribute( mapkey2.toUpperCase(Locale.JAPAN) ) , rowData[vcNo] ) : rowData[vcNo] ;
587                                                if( isAttVal ) {
588                                                        // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
589                                                        final String attVal = (String)getRequestAttribute( mapkey.toUpperCase(Locale.JAPAN) );
590                                                        if( attVal != null && !attVal.isEmpty() ) {
591                                                                rowData[vcNo] = attVal; // RequestAttribute をテーブルに戻す。
592                                                                for( int i=0; i<reqAttClmsNo.length; i++ ) {    // 未設定の場合は、長さゼロの配列。
593                                                                        if( reqAttClmsNo[i] >= 0 ) {
594                                                                                final String reqAtt = (String)getRequestAttribute( reqAttClms[i] );
595                                                                                rowData[reqAttClmsNo[i]] = reqAtt;              // 同時に戻すカラムの値
596                                                                        }
597                                                                }
598                                                        }
599                                                }
600
601                                                final String val = rowData[vcNo] ;
602
603                                                list.add( getMapVals( rowData , val , isNormal , cls , tips , sufix ) );
604                                                restMap.remove( mapkey2 );                      // 6.7.8.0 (2017/04/21) valueMapParam関連
605                                        }
606                                }
607                        }
608                        if( type == 2 ) { Collections.reverse( list ); }        // 逆順
609                        list.forEach( v -> buf.append( v ) );
610                }
611
612                return buf.toString();
613        }
614
615        /**
616         * 指定の文字列バッファから、キーワードのパラメータを取り出します。
617         *
618         * 元の文字列バッファは、そのキーワード部分を削除し、パラメータの値は、RETURNで
619         * 返します。存在しない場合は、null を返します。
620         *
621         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
622         *
623         * @param       keyBuf 文字列バッファ
624         * @param       key キーワード(cls,tips,str)
625         * @return      パラメータ
626         */
627        private String getExtParam( final StringBuilder keyBuf , final String key ) {
628                // key="XXX" 属性の取得
629                String rtn = null;
630                final int ad2 = keyBuf.lastIndexOf( key );                              // = の前後にスペースは入れてはいけない。
631                if( ad2 > 0 ) {
632                        final int st = ad2 + key.length() ;
633                        // cls="B" や、cls='C' のように、文字列指定されているはずなので、その中身を削除します。
634                        final String qot = keyBuf.substring( st,st+1 );         // 1文字取り出す。
635                        final int    ed  = keyBuf.indexOf(  qot,st+1 );         // 対になる後ろのクオートの位置を見つける。
636                        if( ed >= 0 ) {
637                                rtn = keyBuf.substring( st+1 , ed );                    // 前後のクオートは、含まない。
638                                keyBuf.delete( ad2 , ed+1 ) ;                                   // 間を抜く
639                        }
640                        else {
641                                // 文法間違い。どうするか?
642                                System.err.println( "指定の文法が間違っています。key=" + key );
643                        }
644                }
645
646                return rtn;
647        }
648
649        /**
650         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
651         *
652         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
653         *
654         * @return      選択行の配列
655         * @og.rtnNotNull
656         */
657        @Override
658        protected int[] getParameterRows() {
659                final int[] rowNo ;
660                if( selectedAll ) {
661                        final int rowCnt = table.getRowCount();
662                        rowNo = new int[ rowCnt ];
663                        for( int i=0; i<rowCnt; i++ ) {
664                                rowNo[i] = i;
665                        }
666                } else {
667                        rowNo = super.getParameterRows();
668                }
669                return rowNo ;
670        }
671
672        /**
673         * ValueMapParamTagで設定された各種パラメータ を受け取ります。
674         *
675         * @og.rev 6.7.8.0 (2017/04/21) ValueMapParamTag のパラメータを追加します。
676         *
677         * @param       pMap ValueMapParamTagで設定された各種パラメータ
678         */
679        protected void setParam( final ConcurrentMap<VMP_KEYS,String> pMap ) {
680                paramMap.putAll( pMap );                                // ValueMapParamTag と分けるために、内容をコピーします。
681
682                restChangeKey = paramMap.get( VMP_KEYS.REST_CHANGE_KEY );
683        }
684
685        /**
686         * ValueMapParamTagで設定された各種パラメータを元に、残カラムを処理します。
687         *
688         * 処理としては、{&#064;XXXX} の XXXX 部分を、valueMap の未使用キーに変換します。
689         * その後、通常のパラメータ処理を行います。
690         * REST_MARK_CLM が指定されている場合は、DBTableModel に対して、マーク処理を行います。
691         *
692         * @og.rev 6.7.8.0 (2017/04/21) ValueMapParamTag のパラメータを追加します。
693         *
694         * @return      残カラム処理の結果
695         */
696        private String makeRestValue() {
697                // 先にDBTableModel に対して、マーク処理を行います。
698                // パラメータ処理を行うと、キーワードによっては、restMap から値が削除されるためです。
699                final String markClm = paramMap.get( VMP_KEYS.REST_MARK_CLM );
700                final String markVal = paramMap.get( VMP_KEYS.REST_MARK_VAL );
701                if( !restMap.isEmpty() && markClm != null && markVal != null ) {
702                        final int   clmNo = table.getColumnNo( markClm , false );       // ifの階層が深くなるのが嫌なので、まとめてチェックします。
703                        final int[] rowNo = getParameterRows();
704                        if( clmNo >=0 && rowNo.length > 0 ) {
705                                final int[] keysNo = getClmNos( table,keys , 0 );               // keysが指定されない場合は、先頭カラムを使用します。
706
707                                for( int row=0; row<rowNo.length; row++ ) {
708                                        final String[] rowData = table.getValues( row );
709
710                                        // Map に登録されているキーを連結して作成します。
711                                        final String mapkey = getAppendKeys( rowData , keysNo , separator );
712
713                                        if( restMap.containsKey( mapkey ) ) {           // 残っている場合
714                                                table.setValueAt( markVal , row , clmNo );
715                                        }
716                                }
717                        }
718                }
719
720                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
721                if( restMap.isEmpty() ) {
722                        // restMap の残り処理が必要かどうか。restMap が空で、NONE_CLS_KEY が存在する場合は、残を隠す。
723                        useNoneClsKey = paramMap.containsKey( VMP_KEYS.NONE_CLS_KEY );
724                }
725                else {
726                        final String changeVal = paramMap.get( VMP_KEYS.BODY_VAL );
727                        // パラメータ処理を行うと、キーワードによっては、restMap から値が削除されるためです。
728                        final String[] restKeys = restMap.keySet().toArray( new String[restMap.size()] );
729
730                        for( final String key : restKeys ) {
731                                final String repStr = changeVal.replaceAll( "XXXX" , key );
732                                buf.append( getRequestParameter( repStr ) );
733                        }
734                }
735
736                return buf.toString();
737        }
738
739        /**
740         * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
741         *
742         * @og.tag
743         * 全てのデータを選択済みデータとして扱って処理します。
744         * 全件処理する場合に、(true/false)を指定します。
745         * 初期値は false です。
746         *
747         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
748         *
749         * @param  all 選択済み処理可否 [true:全件選択済み/false:通常]
750         */
751        public void setSelectedAll( final String all ) {
752                selectedAll = nval( getRequestParameter( all ),selectedAll );
753        }
754
755        /**
756         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
757         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
758         *
759         * @og.tag
760         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
761         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
762         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
763         * この tableId 属性を利用して、メモリ空間を分けます。
764         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
765         *
766         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
767         *
768         * @param       id テーブルID (sessionに登録する時のID)
769         */
770        public void setTableId( final String id ) {
771                tableId   = nval( getRequestParameter( id ),tableId );
772        }
773
774        /**
775         * 【TAG】パラメータ に登録するキーをセットします。
776         *
777         * @og.tag keysが指定されない場合は、先頭カラムを使用します。
778         *
779         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
780         *
781         * @param       key1 登録キー
782         */
783        public void setKeys( final String key1 ) {
784                keys = nval( getRequestParameter( key1 ),keys ) ;
785        }
786
787        /**
788         * 【TAG】パラメータ から取り出す値カラムを指定ます。
789         *
790         * @og.tag valClmが指定されない場合は、2番目のカラムを使用します。
791         *
792         * @og.rev 6.7.2.0 (2017/01/16) 新規作成
793         *
794         * @param       clm 取り出す値カラム
795         */
796        public void setValClm( final String clm ) {
797                valClm = nval( getRequestParameter( clm ),valClm ) ;
798        }
799
800        /**
801         * 【TAG】パラメータが NULL の時に、設定しないカラム名を、CSV形式で指定します。
802         *
803         * @og.tag 
804         *  nnClms属性:この属性で指定された値が、nullの場合、{&#064;XXXX} の解析を行いません。
805         *  正確に言うと、Mapに取り込みません。この場合、先のholdTag属性で指定したタグそのものも
806         *  出力しません。
807         *
808         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
809         * @og.rev 6.7.2.0 (2017/01/16) 名称変更
810         *
811         * @param       clms NULL の時に、設定しないカラム名を、CSV形式で指定
812         */
813        public void setNnClms( final String clms ) {
814                nnClms = nval( getRequestParameter( clms ),nnClms );
815        }
816
817        /**
818         * 【TAG】値の前後を、挟むタグを指定します。
819         *
820         * @og.tag
821         *  holdTag属性:{&#064;XXXX} を、指定のタグで囲います。
822         *  例えば、holdTag="span" とすると、&lt;span class="YYYYの値" &gt;XXXXの値&lt;/span&gt;
823         *  という文字列を作成します。
824         *  clsClms 属性や、{&#064;XXXX cls="B"} を使用する場合は、holdTag 属性の指定が必要です。
825         *
826         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
827         *
828         * @param       tag 値の前後を挟むタグ
829         * @see         #setClsClms( String )
830         */
831        public void setHoldTag( final String tag ) {
832                holdTag = nval( getRequestParameter( tag ),holdTag );
833        }
834
835        /**
836         * 【TAG】holdTagを使用するとき、そのタグの属性にclass属性を出力する場合のカラム名をCSV形式で指定します。
837         *
838         * @og.tag 
839         *   clsClms属性:先の指定のタグで囲う場合、そのタグのclass属性を指定できます。
840         *   複数指定した場合は、スペースで、連結します。
841         *   一括指定ではなく、個別に指定する場合は、{&#064;XXXX cls="B"} 構文を使用します。
842         *   holdTag属性が設定されていない場合は、どちらも無視されます。
843         *
844         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
845         * @og.rev 6.7.2.0 (2017/01/16) 名称変更
846         *
847         * @param       clms class属性を出力する場合のカラム名を、CSV形式で指定
848         * @see         #setHoldTag( String )
849         */
850        public void setClsClms( final String clms ) {
851                clsClms = nval( getRequestParameter( clms ),clsClms );
852        }
853
854        /**
855         * 【TAG】holdTagを使用するとき、そのタグの属性にtitle属性を出力する場合のカラム名をCSV形式で指定します。
856         *
857         * @og.tag 
858         *   tipsClms属性:先の指定のタグで囲う場合、そのタグのtitle属性を指定できます。
859         *   複数指定した場合は、スペースで、連結します。
860         *   一括指定ではなく、個別に指定する場合は、{&#064;XXXX tips="YYYY"} 構文を使用します。
861         *   holdTag属性が設定されていない場合は、どちらも無視されます。
862         *
863         * @og.rev 6.7.3.0 (2017/01/16) 名称変更
864         *
865         * @param       clms title属性を出力する場合のカラム名を、CSV形式で指定
866         * @see         #setHoldTag( String )
867         */
868        public void setTipsClms( final String clms ) {
869                tipsClms = nval( getRequestParameter( clms ),tipsClms );
870        }
871
872        /**
873         * 【TAG】{&#064;^XXXX}使用時に request.getAttribute() をセットすると同時に設定するカラム名をCSV形式で指定します。
874         *
875         * @og.tag 
876         * DBTableModel と別に、value等で設定した値を、{&#064;^XXXX} で置き換えますが、
877         * その際、DBTableModel のデータも置き換えないと、表示とデータ(例えば、一覧表示やファイル出力時)が異なります。
878         * また、置き換えるに当たって、他の項目(カラム)も置き換えないと、矛盾が生じる恐れがあります。
879         * そこで、request.getAttribute() をセットする場合に、同時にセットするカラムを指定することで、
880         * 同時に値の書き換えを行います。
881         * なお、値は、request.getAttribute() で取得します。
882         *
883         * @og.rev 6.9.2.0 (2018/03/05) 新規作成
884         *
885         * @param       clms request.getAttribute()使用時に、同時に置き換えるカラム名を、CSV形式で指定
886         */
887        public void setReqAttUpClms( final String clms ) {
888                reqAttUpClms = nval( getRequestParameter( clms ),reqAttUpClms );
889        }
890
891        /**
892         * 【TAG】キーとなるカラム名の値を連結する項目区切り文字をセットします(初期値:"_")。
893         *
894         * @og.tag
895         * keysで、複数のキーの値を連結して、Mapのキーにしますが、そのときの連結文字列を指定します。
896         * 初期値は、"_" に設定されています。
897         *
898         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
899         *
900         * @param   sepa 連結文字列 (初期値:"_")
901         */
902        public void setSeparator( final String sepa ) {
903                separator = nval( getRequestParameter( sepa ),separator );
904        }
905
906        /**
907         * 【TAG】パラメータの HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します
908         *              (初期値:USE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
909         *
910         * @og.tag
911         * クロスサイトスクリプティング(XSS)対策の一環としてless/greater than signについてのチェックを行います。
912         * (&gt;&lt;) が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。
913         * (初期値:システム定数のUSE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
914         *
915         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
916         *
917         * @param       flag    XSSチェック [true:する/false:しない]
918         * @see         org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
919         */
920        public void setXssCheck( final String flag ) {
921                xssCheck = nval( getRequestParameter( flag ),xssCheck );
922        }
923
924        /**
925         * このオブジェクトの文字列表現を返します。
926         * 基本的にデバッグ目的に使用します。
927         *
928         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
929         *
930         * @return このクラスの文字列表現
931         * @og.rtnNotNull
932         */
933        @Override
934        public String toString() {
935                return ToString.title( this.getClass().getName() )
936                                .println( "VERSION"                     ,VERSION                )
937                                .println( "tableId"                     ,tableId                )
938                                .println( "selectedAll"         ,selectedAll    )
939                                .println( "keys"                        ,keys                   )
940                                .println( "holdTag"                     ,holdTag                )
941                                .println( "clsClms"                     ,clsClms                )
942                                .println( "tipsClms"            ,tipsClms               )
943                                .println( "valClm"                      ,valClm                 )
944                                .println( "nnClms"                      ,nnClms                 )
945                                .println( "scope"                       ,scope                  )
946                                .println( "separator"           ,separator              )
947                                .println( "xssCheck"            ,xssCheck               )
948                                .println( "Other..."    ,getAttributes().getAttribute() )
949                                .fixForm().toString() ;
950        }
951}