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