    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                for( int i=0; i<clmNo.length; i++ ) {
    406                        final String val = rowData[ clmNo[i] ];
    407                        if( val == null || val.isEmpty() ) {
    408                                rtn = false;
    409                                break;
    410                        }
    411                }
    412                return rtn;
    413        }
    414
    415        /**
    416         * Mapのキーとなるキーカラムの値を連結した値を返します。
    417         *
    418         * @param       rowData 行データ
    419         * @param       clmNo   カラム番号配列
    420         * @param       sep             結合させる文字列
    421         *
    422         * @return      Mapのキーとなるキーカラムの値を連結した値
    423         * @og.rtnNotNull
    424         */
    425        private String getAppendKeys( final String[] rowData , final int[] clmNo , final String sep ) {
    426                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    427
    428                if( clmNo.length > 0 ) {
    429                        buf.append( rowData[ clmNo[0] ] );                              // 最初のひとつ目
    430                        for( int i=1; i<clmNo.length; i++ ) {
    431                                final String val = rowData[ clmNo[i] ];
    432                                if( val != null && !val.isEmpty() ) {
    433                                        buf.append( sep ).append( val );
    434                                }
    435                        }
    436                }
    437                return buf.toString().trim();
    438        }
    439
    440        /**
    441         * Mapの値となる値カラムに対応する文字列配列を返します。
    442         *
    443         * ここでは、行データに対して、配列の添え字(カラム番号)を元に、値を求めます。
    444         * その際、holdTag や、clsClms で指定したクラス名などの付加情報もセットします。
    445         * さらに、{&#064;$XXXX} などの、holdTagの抑止(生データを返す) 処理を行います。
    446         *
    447         * @param       rowData         行の配列データ
    448         * @param       val                     値データ
    449         * @param       isNormal        holdTagを使用せず、ノーマル状態の値を出力するかどうか[true:ノーマルの値]
    450         * @param       cls                     clsClmsNoの使用を抑止し、指定の値を、class属性にセットします。(nullはclsClmsNoを使用、isEmpty() は、classの削除、それ以外は置き換え)
    451         * @param       tips            tipsClmsNoの使用を抑止し、指定の値を、title属性にセットします。(nullはtipsClmsNoを使用、isEmpty() は、titleの削除、それ以外は置き換え)
    452         * @param       sufix           キーのあいまい指定時に、あいまいキー以降の文字列を指定します。あれば、その値を使用します。
    453         *
    454         * @og.rev 6.7.3.0 (2017/01/27) tips 追加
    455         *
    456         * @return      Mapのキーに対応する修飾した値
    457         * @og.rtnNotNull
    458         */
    459        private String getMapVals( final String[] rowData , final String val , final boolean isNormal , final String cls , final String tips , final String sufix ) {
    460                String rtnVal = sufix == null || sufix.isEmpty() ? val : sufix ;
    461
    462                if( !isNormal && holdTag != null && !holdTag.isEmpty() ) {
    463                        // 毎行ごとに、class属性の値は異なる。
    464                        final String clazz = cls  == null ? getAppendKeys( rowData,clsClmsNo ," " ) : cls ;             // class 属性は、スペースで連結
    465                        final String title = tips == null ? getAppendKeys( rowData,tipsClmsNo," " ) : tips ;    // title 属性は、スペースで連結
    466
    467                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    468                        buf.append( '<' ).append( holdTag );
    469                        if( !clazz.isEmpty() ) { buf.append( " class=\"" ).append( clazz ).append( '"' ); }
    470                        if( !title.isEmpty() ) { buf.append( " title=\"" ).append( title ).append( '"' ); }
    471                        buf.append( '>' ).append( rtnVal ).append( "</" ).append( holdTag ).append( '>' );
    472
    473                        rtnVal = buf.toString();
    474                }
    475                return rtnVal ;
    476        }
    477
    478        /**
    479         * リクエスト情報の文字列を取得します。
    480         *
    481         * これは、CommonTagSupportの#getRequestValue( String ) を
    482         * オーバーライドして、Mapから、設定値を取得します。
    483         *
    484         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    485         * @og.rev 6.7.2.0 (2017/01/16) valClm 追加
    486         * @og.rev 6.7.3.0 (2017/01/27) tips 追加
    487         * @og.rev 6.7.6.1 (2017/03/17) 値データを渡すようにします(isAttVal の追加対応)。
    488         * @og.rev 6.7.8.0 (2017/04/21) valueMapParam関連
    489         * @og.rev 6.8.0.1 (2017/06/30) str指定のｷｰﾜｰﾄﾞ
    490         * @og.rev 6.9.2.0 (2018/03/05) reqAttUpClms 追加
    491         *
    492         * @param    key キー
    493         *
    494         * @return   リクエスト情報の文字列
    495         * @see         CommonTagSupport#getRequestValue( String )
    496         */
    497        @Override
    498        protected String getRequestValue( final String key ) {
    499                if( key.equals( restChangeKey ) ) { return makeRestValue(); }           // 6.7.8.0 (2017/04/21)
    500
    501                // {@!XXXX} や、{@*XXXX!*} の場合のキー対応。最初に行う。
    502                final char ch1 = key.charAt(0);
    503                final boolean isNormal = ch1 == '$' ;           // holdTag を使わず、値そのものを出します。
    504                final boolean isSufix  = ch1 == '*' ;           // あいまい検索時に、あいまいで削除された部分文字列を使うかどうか。
    505                final boolean isAttVal = ch1 == '^' ;           // 値を、request.getAttribute()の値を優先して使用します。
    506
    507                final StringBuilder keyBuf = new StringBuilder( key.trim() );
    508
    509                if( isNormal || isSufix || isAttVal ) { keyBuf.deleteCharAt( 0 ); }             // 先頭の文字を削除
    510
    511                // カラム番号の取得のための分割。存在する場合は、必ず一番最後にします。
    512                final int ad1  = keyBuf.lastIndexOf( " " );             // 後ろから検索して、スペースで分割
    513                int       vcNo = valClmNo;
    514                if( ad1 > 0 ) {
    515                        // 必要かどうかはともかく、NumberFormatException で、判定すると、遅くなる気がする。
    516                        final char ch = keyBuf.charAt( ad1 + 1 );       // 数字であろう先頭文字
    517                        if( '0' <= ch && ch <= '9' ) {
    518                                try {
    519                                        vcNo   = Integer.parseInt( keyBuf.substring( ad1 + 1 ) );
    520                                        keyBuf.setLength( ad1 );                                                                        // ｽﾍﾟｰｽが残っている可能性がある
    521                                }
    522                                catch( final NumberFormatException ex ) {               // 数値変換失敗時は、普通のパラメータだった場合。
    523        //                              vcNo   = valClmNo;              // vcNo は、セットする前にException が発生している。
    524        //                              mapkey = key;                   // mapkey は、スペースも含むすべてのキーになる。･････ NumberFormatException が先なので、setLength されていない。
    525                                }
    526                        }
    527                }
    528
    529                // cls="B" 属性の取得
    530                final String cls = getExtParam( keyBuf,CLS_KEY );               // 6.8.0.1 (2017/06/30) 関数化
    531
    532                // 6.7.3.0 (2017/01/27) tips="YYYY" 属性の取得
    533                final String tips = getExtParam( keyBuf,TIPS_KEY );             // 6.8.0.1 (2017/06/30) 関数化
    534
    535                // 6.8.0.1 (2017/06/30) str指定のｷｰﾜｰﾄﾞ。先に取り除かないと、type 判定時の endsWith が効かない。
    536                final String instr = getExtParam( keyBuf,STR_KEY );
    537
    538                // 中途半端に、ｽﾍﾟｰｽが残っていると厄介なので、削除しておきます。
    539                final String mapkey = keyBuf.toString().trim();
    540
    541                // type==0 は、ｵﾘｼﾞﾅﾙ。それ以外は、キーから取り除く文字数
    542                final int type = mapkey.endsWith( "!*" ) ? 2 : mapkey.endsWith( "*" ) ? 1 : 0 ;
    543
    544                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    545                if( type == 0 ) {
    546                        final String[] rowData = mapObj.get( mapkey );
    547                        restMap.remove( mapkey );                                                       // 6.7.8.0 (2017/04/21) valueMapParam関連
    548
    549                        if( rowData != null && vcNo < rowData.length ) {
    550                                // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
    551                                // 6.9.2.0 (2018/03/05) DBTableModel への値のﾌｨｰﾄﾞﾊﾞｯｸ
    552//                              final String val = isAttVal ? nval( (String)getRequestAttribute( mapkey.toUpperCase(Locale.JAPAN) ) , rowData[vcNo] ) : rowData[vcNo] ;
    553                                if( isAttVal ) {
    554                                        // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
    555                                        final String attVal = (String)getRequestAttribute( mapkey.toUpperCase(Locale.JAPAN) );
    556                                        if( attVal != null && !attVal.isEmpty() ) {
    557                                                rowData[vcNo] = attVal; // RequestAttribute をﾃｰﾌﾞﾙに戻す。
    558                                                for( int i=0; i<reqAttClmsNo.length; i++ ) {    // 未設定の場合は、長さゼロの配列。
    559                                                        if( reqAttClmsNo[i] >= 0 ) {
    560                                                                final String reqAtt = (String)getRequestAttribute( reqAttClms[i] );
    561                                                                rowData[reqAttClmsNo[i]] = reqAtt;              // 同時に戻すカラムの値
    562                                                        }
    563                                                }
    564                                        }
    565                                }
    566
    567                                final String val = rowData[vcNo] ;
    568
    569                                buf.append( getMapVals( rowData , val , isNormal , cls , tips , null ) );
    570                        }
    571                        else {
    572                                buf.append( super.getRequestValue( key , xssCheck ) );                          // 添字も合わせて、上位に問い合わせる。
    573                        }
    574                }
    575                else {
    576                        final String subKey = mapkey.substring( 0,mapkey.length()-type );               // ほんとは、keyBuf で処理したかった。
    577                        final List<String> list = new ArrayList<>();
    578                        for( final Map.Entry<String,String[]> entry : mapObj.entrySet() ) {             // {@XXXX}を見つける都度、全Mapをスキャンしているので、非効率
    579                                final String mapkey2 = entry.getKey();
    580                                // 6.8.0.1 (2017/06/30) str指定のｷｰﾜｰﾄﾞ
    581                                if( mapkey2.startsWith( subKey ) && ( instr == null || mapkey2.contains( instr ) ) ) {
    582                                        final String[] rowData = entry.getValue();
    583                                        if( rowData != null && vcNo < rowData.length ) {
    584                                                final String sufix = isSufix ? mapkey2.substring( subKey.length() ) : null ;    // あいまいキーの残りの文字列
    585                                                // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
    586                                                // 6.9.2.0 (2018/03/05) DBTableModel への値のﾌｨｰﾄﾞﾊﾞｯｸ
    587//                                              final String val   = isAttVal ? nval( (String)getRequestAttribute( mapkey2.toUpperCase(Locale.JAPAN) ) , rowData[vcNo] ) : rowData[vcNo] ;
    588                                                if( isAttVal ) {
    589                                                        // isAttVal == true のときは、RequestAttribute から取り出すが、キーは、大文字になっているので注意。
    590                                                        final String attVal = (String)getRequestAttribute( mapkey.toUpperCase(Locale.JAPAN) );
    591                                                        if( attVal != null && !attVal.isEmpty() ) {
    592                                                                rowData[vcNo] = attVal; // RequestAttribute をﾃｰﾌﾞﾙに戻す。
    593                                                                for( int i=0; i<reqAttClmsNo.length; i++ ) {    // 未設定の場合は、長さゼロの配列。
    594                                                                        if( reqAttClmsNo[i] >= 0 ) {
    595                                                                                final String reqAtt = (String)getRequestAttribute( reqAttClms[i] );
    596                                                                                rowData[reqAttClmsNo[i]] = reqAtt;              // 同時に戻すカラムの値
    597                                                                        }
    598                                                                }
    599                                                        }
    600                                                }
    601
    602                                                final String val = rowData[vcNo] ;
    603
    604                                                list.add( getMapVals( rowData , val , isNormal , cls , tips , sufix ) );
    605                                                restMap.remove( mapkey2 );                      // 6.7.8.0 (2017/04/21) valueMapParam関連
    606                                        }
    607                                }
    608                        }
    609                        if( type == 2 ) { Collections.reverse( list ); }        // 逆順
    610                        list.forEach( v -> buf.append( v ) );
    611                }
    612
    613                return buf.toString();
    614        }
    615
    616        /**
    617         * 指定の文字列バッファから、キーワードのパラメータを取り出します。
    618         *
    619         * 元の文字列バッファは、そのキーワード部分を削除し、パラメータの値は、RETURNで
    620         * 返します。存在しない場合は、null を返します。
    621         *
    622         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    623         *
    624         * @param       keyBuf 文字列バッファ
    625         * @param       key キーワード(cls,tips,str)
    626         * @return      パラメータ
    627         */
    628        private String getExtParam( final StringBuilder keyBuf , final String key ) {
    629                // key="XXX" 属性の取得
    630                String rtn = null;
    631                final int ad2 = keyBuf.lastIndexOf( key );                              // = の前後にｽﾍﾟｰｽは入れてはいけない。
    632                if( ad2 > 0 ) {
    633                        final int st = ad2 + key.length() ;
    634                        // cls="B" や、cls='C' のように、文字列指定されているはずなので、その中身を削除します。
    635                        final String qot = keyBuf.substring( st,st+1 );         // １文字取り出す。
    636                        final int    ed  = keyBuf.indexOf(  qot,st+1 );         // 対になる後ろのクオートの位置を見つける。
    637                        if( ed >= 0 ) {
    638                                rtn = keyBuf.substring( st+1 , ed );                    // 前後のクオートは、含まない。
    639                                keyBuf.delete( ad2 , ed+1 ) ;                                   // 間を抜く
    640                        }
    641                        else {
    642                                // 文法間違い。どうするか？
    643                                System.err.println( "指定の文法が間違っています。key=" + key );
    644                        }
    645                }
    646
    647                return rtn;
    648        }
    649
    650        /**
    651         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
    652         *
    653         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    654         *
    655         * @return      選択行の配列
    656         * @og.rtnNotNull
    657         */
    658        @Override
    659        protected int[] getParameterRows() {
    660                final int[] rowNo ;
    661                if( selectedAll ) {
    662                        final int rowCnt = table.getRowCount();
    663                        rowNo = new int[ rowCnt ];
    664                        for( int i=0; i<rowCnt; i++ ) {
    665                                rowNo[i] = i;
    666                        }
    667                } else {
    668                        rowNo = super.getParameterRows();
    669                }
    670                return rowNo ;
    671        }
    672
    673        /**
    674         * ValueMapParamTagで設定された各種パラメータ を受け取ります。
    675         *
    676         * @og.rev 6.7.8.0 (2017/04/21) ValueMapParamTag のパラメータを追加します。
    677         *
    678         * @param       pMap ValueMapParamTagで設定された各種パラメータ
    679         */
    680        protected void setParam( final ConcurrentMap<VMP_KEYS,String> pMap ) {
    681                paramMap.putAll( pMap );                                // ValueMapParamTag と分けるために、内容をコピーします。
    682
    683                restChangeKey = paramMap.get( VMP_KEYS.REST_CHANGE_KEY );
    684        }
    685
    686        /**
    687         * ValueMapParamTagで設定された各種パラメータを元に、残カラムを処理します。
    688         *
    689         * 処理としては、{&#064;XXXX} の XXXX 部分を、valueMap の未使用キーに変換します。
    690         * その後、通常のパラメータ処理を行います。
    691         * REST_MARK_CLM が指定されている場合は、DBTableModel に対して、マーク処理を行います。
    692         *
    693         * @og.rev 6.7.8.0 (2017/04/21) ValueMapParamTag のパラメータを追加します。
    694         * @og.rev 6.9.9.0 (2018/08/20) YYYYｷｰﾜｰﾄﾞに置換するｸﾞﾙｰﾌﾟｶﾗﾑ名
    695         * @og.rev 6.9.9.2 (2018/09/18) YYYYｷｰﾜｰﾄﾞで、@のあるなしを対処しておきます(前方一致の必要性)。
    696         *
    697         * @return      残カラム処理の結果
    698         */
    699        private String makeRestValue() {
    700                // 先にDBTableModel に対して、マーク処理を行います。
    701                // パラメータ処理を行うと、キーワードによっては、restMap から値が削除されるためです。
    702                final String markClm = paramMap.get( VMP_KEYS.REST_MARK_CLM );
    703                final String markVal = paramMap.get( VMP_KEYS.REST_MARK_VAL );
    704                if( !restMap.isEmpty() && markClm != null && markVal != null ) {
    705                        final int   clmNo = table.getColumnNo( markClm , false );       // ifの階層が深くなるのが嫌なので、まとめてチェックします。
    706                        final int[] rowNo = getParameterRows();
    707                        if( clmNo >=0 && rowNo.length > 0 ) {
    708                                final int[] keysNo = getClmNos( table,keys , 0 );               // keysが指定されない場合は、先頭カラムを使用します。
    709
    710                                for( int row=0; row<rowNo.length; row++ ) {
    711                                        final String[] rowData = table.getValues( row );
    712
    713                                        // Map に登録されているキーを連結して作成します。
    714                                        final String mapkey = getAppendKeys( rowData , keysNo , separator );
    715
    716                                        if( restMap.containsKey( mapkey ) ) {                           // 残っている場合
    717                                                table.setValueAt( markVal , row , clmNo );
    718                                        }
    719                                }
    720                        }
    721                }
    722
    723                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    724                if( restMap.isEmpty() ) {
    725                        // restMap の残り処理が必要かどうか。restMap が空で、NONE_CLS_KEY が存在する場合は、残を隠す。
    726                        useNoneClsKey = paramMap.containsKey( VMP_KEYS.NONE_CLS_KEY );
    727                }
    728                else {
    729                        final String changeVal = paramMap.get( VMP_KEYS.BODY_VAL );
    730                        // パラメータ処理を行うと、キーワードによっては、restMap から値が削除されるためです。
    731                        final String[] restKeys = restMap.keySet().toArray( new String[restMap.size()] );
    732
    733                        final String grpClm   = paramMap.get( VMP_KEYS.GRP_KEY_CLM );           // 6.9.9.0 (2018/08/20)
    734                        final int    grpClmNo = table.getColumnNo( grpClm , false );            // 6.9.9.0 (2018/08/20) 無ければ、-1
    735
    736                        // 6.9.9.0 (2018/08/20) YYYYｷｰﾜｰﾄﾞに置換するｸﾞﾙｰﾌﾟｶﾗﾑ名 対応
    737                        for( final String key : restKeys ) {
    738                                final String repStr = changeVal.replaceAll( "XXXX" , key );
    739
    740                                if( grpClmNo < 0 ) {
    741                                        buf.append( getRequestParameter( repStr ) );                            // 従来どおり、YYYY 処理を行わない。
    742                                }
    743                                else {
    744                                        final String[] vals = restMap.get( key );
    745                                        if( vals == null ) { continue; }                                                        // ｸﾞﾙｰﾌﾟ処理で、未処理データが使用済みになった。
    746                                        final String grpKey = vals[grpClmNo];
    747                                        final String repStr2 = repStr.replaceAll( "YYYY" , grpKey );
    748
    749                                        buf.append( getRequestParameter( repStr2 ) );
    750                                }
    751                        }
    752
    753//                      // 6.9.9.0 (2018/08/20)
    754//                      for( final String key : restKeys ) {
    755//                              final String repStr = changeVal.replaceAll( "XXXX" , key );
    756//                              buf.append( getRequestParameter( repStr ) );
    757//                      }
    758                }
    759
    760                return buf.toString();
    761        }
    762
    763        /**
    764         * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
    765         *
    766         * @og.tag
    767         * 全てのデータを選択済みデータとして扱って処理します。
    768         * 全件処理する場合に、(true/false)を指定します。
    769         * 初期値は false です。
    770         *
    771         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    772         *
    773         * @param  all 選択済み処理可否 [true:全件選択済み/false:通常]
    774         */
    775        public void setSelectedAll( final String all ) {
    776                selectedAll = nval( getRequestParameter( all ),selectedAll );
    777        }
    778
    779        /**
    780         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    781         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    782         *
    783         * @og.tag
    784         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
    785         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
    786         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
    787         * この tableId 属性を利用して、メモリ空間を分けます。
    788         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    789         *
    790         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    791         *
    792         * @param       id テーブルID (sessionに登録する時のID)
    793         */
    794        public void setTableId( final String id ) {
    795                tableId   = nval( getRequestParameter( id ),tableId );
    796        }
    797
    798        /**
    799         * 【TAG】パラメータ に登録するキーをセットします。
    800         *
    801         * @og.tag keysが指定されない場合は、先頭カラムを使用します。
    802         *
    803         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    804         *
    805         * @param       key1 登録キー
    806         */
    807        public void setKeys( final String key1 ) {
    808                keys = nval( getRequestParameter( key1 ),keys ) ;
    809        }
    810
    811        /**
    812         * 【TAG】パラメータ から取り出す値カラムを指定ます。
    813         *
    814         * @og.tag valClmが指定されない場合は、２番目のカラムを使用します。
    815         *
    816         * @og.rev 6.7.2.0 (2017/01/16) 新規作成
    817         *
    818         * @param       clm 取り出す値カラム
    819         */
    820        public void setValClm( final String clm ) {
    821                valClm = nval( getRequestParameter( clm ),valClm ) ;
    822        }
    823
    824        /**
    825         * 【TAG】パラメータが NULL の時に、設定しないカラム名を、CSV形式で指定します。
    826         *
    827         * @og.tag
    828         *  nnClms属性：この属性で指定された値が、nullの場合、{&#064;XXXX} の解析を行いません。
    829         *  正確に言うと、Mapに取り込みません。この場合、先のholdTag属性で指定したタグそのものも
    830         *  出力しません。
    831         *
    832         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    833         * @og.rev 6.7.2.0 (2017/01/16) 名称変更
    834         *
    835         * @param       clms NULL の時に、設定しないカラム名を、CSV形式で指定
    836         */
    837        public void setNnClms( final String clms ) {
    838                nnClms = nval( getRequestParameter( clms ),nnClms );
    839        }
    840
    841        /**
    842         * 【TAG】値の前後を、挟むタグを指定します。
    843         *
    844         * @og.tag
    845         *  holdTag属性：{&#064;XXXX} を、指定のタグで囲います。
    846         *  例えば、holdTag="span" とすると、&lt;span class="YYYYの値" &gt;XXXXの値&lt;/span&gt;
    847         *  という文字列を作成します。
    848         *  clsClms 属性や、{&#064;XXXX cls="B"} を使用する場合は、holdTag 属性の指定が必要です。
    849         *
    850         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    851         *
    852         * @param       tag 値の前後を挟むタグ
    853         * @see         #setClsClms( String )
    854         */
    855        public void setHoldTag( final String tag ) {
    856                holdTag = nval( getRequestParameter( tag ),holdTag );
    857        }
    858
    859        /**
    860         * 【TAG】holdTagを使用するとき、そのタグの属性にclass属性を出力する場合のカラム名をCSV形式で指定します。
    861         *
    862         * @og.tag
    863         *   clsClms属性：先の指定のタグで囲う場合、そのタグのclass属性を指定できます。
    864         *   複数指定した場合は、スペースで、連結します。
    865         *   一括指定ではなく、個別に指定する場合は、{&#064;XXXX cls="B"} 構文を使用します。
    866         *   holdTag属性が設定されていない場合は、どちらも無視されます。
    867         *
    868         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    869         * @og.rev 6.7.2.0 (2017/01/16) 名称変更
    870         *
    871         * @param       clms class属性を出力する場合のカラム名を、CSV形式で指定
    872         * @see         #setHoldTag( String )
    873         */
    874        public void setClsClms( final String clms ) {
    875                clsClms = nval( getRequestParameter( clms ),clsClms );
    876        }
    877
    878        /**
    879         * 【TAG】holdTagを使用するとき、そのタグの属性にtitle属性を出力する場合のカラム名をCSV形式で指定します。
    880         *
    881         * @og.tag
    882         *   tipsClms属性：先の指定のタグで囲う場合、そのタグのtitle属性を指定できます。
    883         *   複数指定した場合は、スペースで、連結します。
    884         *   一括指定ではなく、個別に指定する場合は、{&#064;XXXX tips="YYYY"} 構文を使用します。
    885         *   holdTag属性が設定されていない場合は、どちらも無視されます。
    886         *
    887         * @og.rev 6.7.3.0 (2017/01/16) 名称変更
    888         *
    889         * @param       clms title属性を出力する場合のカラム名を、CSV形式で指定
    890         * @see         #setHoldTag( String )
    891         */
    892        public void setTipsClms( final String clms ) {
    893                tipsClms = nval( getRequestParameter( clms ),tipsClms );
    894        }
    895
    896        /**
    897         * 【TAG】{&#064;^XXXX}使用時に request.getAttribute() をセットすると同時に設定するカラム名をCSV形式で指定します。
    898         *
    899         * @og.tag
    900         * DBTableModel と別に、value等で設定した値を、{&#064;^XXXX} で置き換えますが、
    901         * その際、DBTableModel のﾃﾞｰﾀも置き換えないと、表示とﾃﾞｰﾀ(例えば、一覧表示やﾌｧｲﾙ出力時)が異なります。
    902         * また、置き換えるに当たって、他の項目(カラム)も置き換えないと、矛盾が生じる恐れがあります。
    903         * そこで、request.getAttribute() をセットする場合に、同時にセットするカラムを指定することで、
    904         * 同時に値の書き換えを行います。
    905         * なお、値は、request.getAttribute() で取得します。
    906         *
    907         * @og.rev 6.9.2.0 (2018/03/05) 新規作成
    908         *
    909         * @param       clms request.getAttribute()使用時に、同時に置き換えるカラム名を、CSV形式で指定
    910         */
    911        public void setReqAttUpClms( final String clms ) {
    912                reqAttUpClms = nval( getRequestParameter( clms ),reqAttUpClms );
    913        }
    914
    915        /**
    916         * 【TAG】キーとなるカラム名の値を連結する項目区切り文字をセットします(初期値:"_")。
    917         *
    918         * @og.tag
    919         * keysで、複数のキーの値を連結して、Mapのキーにしますが、そのときの連結文字列を指定します。
    920         * 初期値は、"_" に設定されています。
    921         *
    922         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    923         *
    924         * @param   sepa 連結文字列 (初期値:"_")
    925         */
    926        public void setSeparator( final String sepa ) {
    927                separator = nval( getRequestParameter( sepa ),separator );
    928        }
    929
    930        /**
    931         * 【TAG】パラメータの HTMLTag開始/終了文字(&gt;&lt;) 存在チェックを実施するかどうか[true/false]を設定します
    932         *              (初期値:USE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
    933         *
    934         * @og.tag
    935         * クロスサイトスクリプティング(XSS)対策の一環としてless/greater than signについてのチェックを行います。
    936         * (&gt;&lt;) が含まれていたエラーにする(true)／かノーチェックか(false)を指定します。
    937         * (初期値:システム定数のUSE_XSS_CHECK[={@og.value SystemData#USE_XSS_CHECK}])。
    938         *
    939         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    940         *
    941         * @param       flag    XSSチェック [true:する/false:しない]
    942         * @see         org.opengion.hayabusa.common.SystemData#USE_XSS_CHECK
    943         */
    944        public void setXssCheck( final String flag ) {
    945                xssCheck = nval( getRequestParameter( flag ),xssCheck );
    946        }
    947
    948        /**
    949         * このオブジェクトの文字列表現を返します。
    950         * 基本的にデバッグ目的に使用します。
    951         *
    952         * @og.rev 6.7.1.0 (2017/01/05) 新規作成
    953         *
    954         * @return このクラスの文字列表現
    955         * @og.rtnNotNull
    956         */
    957        @Override
    958        public String toString() {
    959                return ToString.title( this.getClass().getName() )
    960                                .println( "VERSION"                     ,VERSION                )
    961                                .println( "tableId"                     ,tableId                )
    962                                .println( "selectedAll"         ,selectedAll    )
    963                                .println( "keys"                        ,keys                   )
    964                                .println( "holdTag"                     ,holdTag                )
    965                                .println( "clsClms"                     ,clsClms                )
    966                                .println( "tipsClms"            ,tipsClms               )
    967                                .println( "valClm"                      ,valClm                 )
    968                                .println( "nnClms"                      ,nnClms                 )
    969                                .println( "scope"                       ,scope                  )
    970                                .println( "separator"           ,separator              )
    971                                .println( "xssCheck"            ,xssCheck               )
    972                                .println( "Other..."    ,getAttributes().getAttribute() )
    973                                .fixForm().toString() ;
    974        }
    975}