    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 java.io.IOException;
    019import java.util.ArrayList;
    020import java.util.HashMap;
    021import java.util.List;
    022import java.util.Locale;
    023import java.util.Map;
    024import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
    025
    026import javax.script.ScriptEngine;
    027import javax.script.ScriptEngineManager;
    028import javax.script.ScriptException;
    029import javax.servlet.ServletException;
    030
    031import org.opengion.fukurou.db.DBUtil;
    032import org.opengion.fukurou.db.Transaction;
    033import org.opengion.fukurou.model.Formatter;
    034import org.opengion.fukurou.util.ErrorMessage;
    035import org.opengion.fukurou.util.StringUtil;
    036import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
    037import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
    038import org.opengion.hayabusa.common.HybsSystem;
    039import org.opengion.hayabusa.common.HybsSystemException;
    040import org.opengion.hayabusa.db.DBTableModel;
    041import org.opengion.hayabusa.resource.ResourceManager;
    042
    043import static org.opengion.fukurou.util.StringUtil.nval;
    044
    045/**
    046 * 画面で入力されたデータのチェックを行うためのタグです。
    047 *
    048 * commandがNEWの場合は検索条件等のリクエストパラメータに対してチェックを行います。
    049 * commandがENTRYの場合は、登録時のDBテーブルモデルに対するチェックを行います。
    050 * (値の取得は、先に選択された行のみについて、実行されます。)
    051 *
    052 * チェックを行うための定義は、SQL文 又は JavaScriptの式が記述可能です。
    053 * これらの式はタグのボディー部分に記述します。
    054 *
    055 * SQL文によりチェックを行う場合は、必ず件数が返されるように記述して下さい(select count(*) ･･･ 等)
    056 * このSQL文で取得された件数とexistの属性値とを照合しチェックを行います。
    057 * いずれの場合も、成立時は、正常とみなします。
    058 * (｢true:存在する｣ には、データが存在した場合に、ＯＫで、なければエラーです。)
    059 *
    060 * JavaScript式を記述する場合は、必ずtrue or falseを返す式を指定して下さい。
    061 * この式を評価した結果falseが返される場合は、エラーとみなします。
    062 * 式に不等号等を使用する場合は、CDATAセクションで囲うようにして下さい。
    063 *
    064 * また、いずれのチェック方法の場合でも、引数部に[カラム名]を用いたHybs拡張SQL文を
    065 * 指定することが可能です。
    066 * メッセージIDの{0},{1}にはそれぞれ[カラム名]指定されたカラム名及びデータがCSV形式で
    067 * 自動的に設定されます。
    068 *
    069 * ※ このタグは、Transaction タグの対象です。
    070 *
    071 * @og.formSample
    072 * <pre>
    073 * ●形式：
    074 *       ・&lt;og:dataCheck
    075 *                    command       = "{&#064;command}"
    076 *                    exist         = "[auto|true|false|one|notuse]"
    077 *                    errRemove     = "[true|false]"
    078 *                    lbl           = "{&#064;lbl}"
    079 *                    lblParamKeys  = "ZY03"      : メッセージリソースのキーをCSV形式で指定。{2} 以降にセット
    080 *                    sqlType       = "{&#064;sqlType}"
    081 *                    execType      = "INSERT|COPY|UPDATE|MODIFY|DELETE"  : sqlType を含む場合、実行
    082 *                    conditionKey  = "FGJ"        : 条件判定するカラムＩＤを指定(初期値は columnId )
    083 *                    conditionList = "0|1|8|9"    : 条件判定する値のリストを、"|"で区切って登録(初期値は、無条件)
    084 *                    uniqCheckClms = "CLM,LANG"   : DBTableModel内でのユニークキーチェックを行うためのカラム
    085 *         &gt;
    086 *
    087 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    088 *         (SQL文 又は JavaScript式)
    089 *       ：なし( from属性、where属性を使用して、SQL文を内部で作成します)
    090 *
    091 * ●Tag定義：
    092 *   &lt;og:dataCheck
    093 *       command            【TAG】コマンド (NEW or ENTRY)をセットします
    094 *       exist              【TAG】データベースのチェック方法[auto/true/false/one/notuse]を指定します(初期値:auto[自動])
    095 *       tableId            【TAG】(通常は使いません)結果をDBTableModelに書き込んで、sessionに登録するときのキーを指定します
    096 *       dbid               【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します(初期値:null)
    097 *       lbl                【TAG】ラベルリソースIDを指定します
    098 *       lblParamKeys       【TAG】ラベルリソースの引数をCSV形式で指定します
    099 *       errRemove          【TAG】エラー時の選択行を取り除いて継続処理を行うかどうか[true/false]を指定します(初期値:false)
    100 *       sqlType            【TAG】このチェックを行う、SQLタイプ を指定します
    101 *       execType           【TAG】このチェックを行う、実行タイプ を指定します
    102 *       conditionKey       【TAG】条件判定するカラムＩＤを指定します
    103 *       conditionList      【TAG】条件判定する値のリストを、"|"で区切って登録します(初期値:無条件)
    104 *       uniqCheckClms      【TAG】指定されたキーに従って、メモリ上のテーブルに対してユニークキーチェックを行います
    105 *       beforeErrorJsp     【TAG】エラーが発生した際に、エラーメッセージの表示前にincludeするJSPを指定します
    106 *       afterErrorJsp      【TAG】エラーが発生した際に、エラーメッセージの表示後にincludeするJSPを指定します
    107 *       selectedAll        【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
    108 *       from               【TAG】tableExist タグ廃止に伴う、簡易機能追加。チェックするデータベース名(from 句)を指定します。
    109 *       where              【TAG】tableExist タグ廃止に伴う、簡易機能追加。チェックする検索条件(where句)を指定します。
    110 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    111 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
    112 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
    113 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
    114 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
    115 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
    116 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    117 *   &gt;   ... Body ...
    118 *   &lt;/og:dataCheck&gt;
    119 *
    120 * 【廃止】6.9.0.0 (2018/01/31) 物理削除
    121 *   //  msg                【廃止】メッセージIDを指定します(lbl 属性を使用してください)
    122 *   //  msgParamKeys       【廃止】メッセージリソースの引数をCSV形式で指定します(lblParamKeys 属性を使用してください)
    123 *
    124 * ●使用例
    125 *       ・&lt;og:dataCheck
    126 *                    command   = "ENTRY"
    127 *                    exist     = "true"
    128 *                    lbl       = "MSG0001"
    129 *         &gt;
    130 *             select count(*) from GEA03 where clm = [CLM]
    131 *         &lt;/og:dataCheck&gt;
    132 *
    133 *          ・exist 属性の値に応じて、チェック方法が異なります。
    134 *            [ auto , true , false , one , notuse が指定できます。]
    135 *
    136 *       ・&lt;og:dataCheck
    137 *                    command   = "ENTRY"
    138 *                    lbl       = "MSG0001"
    139 *         &gt;
    140 *           &lt;![CDATA[
    141 *             [DYSTART] &lt; [DY] &amp;&amp; [DY] &lt; [DYEND]
    142 *           ]]&gt;
    143 *         &lt;/og:dataCheck&gt;
    144 *
    145 *         ・&lt;og:dataCheck
    146 *                    command   = "ENTRY"
    147 *                    lbl       = "MSG0001"
    148 *         &gt;
    149 *           &lt;![CDATA[
    150 *             [GOKEI] &lt; [TANKA] * [RITU]
    151 *           ]]&gt;
    152 *         &lt;/og:dataCheck&gt;
    153 *
    154 *    ※ og:tableExist タグが廃止されました。og:dataCheckタグで置き換えてください。
    155 *       ・&lt;og:tableExist
    156 *                    command = "{&#064;command}"
    157 *                    names   = "USERID,SYSTEM_ID"
    158 *                    from    = "GE10"
    159 *                    where   = "USERID=? AND SYSTEM_ID=?"
    160 *                    exist   = "true"
    161 *         /&gt;
    162 *
    163 *        ⇒
    164 *       ・&lt;og:dataCheck
    165 *                    command = "{&#064;command}"
    166 *                    exist   = "true"
    167 *                    from    = "GE10"
    168 *                    where   = "USERID=[USERID] AND SYSTEM_ID=[SYSTEM_ID]"
    169 *         /&gt;
    170 *
    171 *       ・&lt;og:tableExist
    172 *                    command = "{&#064;command}"
    173 *                    from    = "GE10"
    174 *                    where   = "USERID=[USERID] AND SYSTEM_ID=[SYSTEM_ID]"  /&gt;
    175 *        ⇒
    176 *       ・&lt;og:dataCheck
    177 *                    command = "{&#064;command}"
    178 *                    from    = "GE10"
    179 *                    where   = "USERID=[USERID] AND SYSTEM_ID=[SYSTEM_ID]"  /&gt;
    180 *         /&gt;
    181 *
    182 * </pre>
    183 *
    184 * @og.rev 4.1.1.1 (2008/02/22) 新規作成
    185 * @og.group ＤＢ登録
    186 *
    187 * @version  4.0
    188 * @author       Hiroki Nakamura
    189 * @since    JDK5.0,
    190 */
    191public class DataCheckTag extends CommonTagSupport {
    192        /** このプログラムのVERSION文字列を設定します。   {@value} */
    193        private static final String VERSION = "7.0.7.0 (2019/12/13)" ;
    194        private static final long serialVersionUID = 707020191213L ;
    195
    196        /** command 引数に渡す事の出来る コマンド {@value} */
    197        public static final String              CMD_NEW                         = "NEW";
    198
    199        /** command 引数に渡す事の出来る コマンド {@value} */
    200        public static final String              CMD_ENTRY                       = "ENTRY";
    201
    202        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    203        private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_ENTRY, CMD_NEW );
    204
    205        /** 内部変数 */
    206        private transient DBTableModel  table           ;
    207        private transient boolean               isSql           ;
    208        private transient boolean               isUniqCheck     ;               // 4.3.4.0 (2008/12/01) 追加
    209        private transient ScriptEngine  jsEngine        ;
    210        private transient String                bodyStr         ;               // 4.3.4.0 (2008/12/01) 追加
    211
    212        /** タグで設定する属性 */
    213        private String          command                 = CMD_ENTRY;
    214        private String          exist                   = "auto";
    215        private String          tableId                 = HybsSystem.TBL_MDL_KEY;
    216        private String          dbid                    ;
    217        private String          lbl                             ;
    218        private String[]        lblParamKeys    ;                       // 4.2.0.1 (2008/03/27)
    219        private boolean         errRemove               ;
    220        private String          sqlType                 ;                       // INSERT,COPY,UPDATE,MODIFY,DELETE
    221        private String          execType                ;                       // INSERT,COPY,UPDATE,MODIFY,DELETE
    222
    223        private String          conditionKey    ;                       // 4.2.0.1 (2008/03/27)
    224        private String          conditionList   ;                       // 4.2.0.1 (2008/03/27)
    225        private String          from                    ;                       // 4.2.0.1 (2008/03/27)
    226        private String          where                   ;                       // 5.7.6.2 (2014/05/16) tableExist タグに伴う便利機能追加
    227        private String[]        uniqCheckClms   ;                       // 4.3.4.0 (2008/12/01)
    228
    229        private String          beforeErrorJsp  ;                       // 5.1.9.0 (2010/08/01)
    230        private String          afterErrorJsp   ;                       // 5.1.9.0 (2010/08/01)
    231        private boolean         selectedAll             ;                       // 5.1.9.0 (2010/08/01)
    232
    233        private boolean         isExec                  ;                       // 6.3.4.0 (2015/08/01) パラメータではなく毎回設定します。
    234
    235        private boolean         useSLabel               ;                       // 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    236
    237        /**
    238         * デフォルトコンストラクター
    239         *
    240         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    241         */
    242        public DataCheckTag() { super(); }              // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    243
    244        /**
    245         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    246         *
    247         * @og.rev 4.1.1.0 (2008/02/22) 新規作成
    248         * @og.rev 4.1.2.0 (2008/03/12) sqlType,execType 判定
    249         * @og.rev 6.3.4.0 (2015/08/01) caseKey,caseVal,caseNN,caseNull,caseIf 属性対応
    250         *
    251         * @return      後続処理の指示
    252         */
    253        @Override
    254        public int doStartTag() {
    255                isExec = useTag() && ( sqlType == null || execType == null || execType.indexOf( sqlType ) >= 0 ) ;
    256
    257                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    258                return isExec
    259                                        ? EVAL_BODY_BUFFERED            // Body を評価する
    260                                        : SKIP_BODY ;                           // Body を評価しない
    261        }
    262
    263        /**
    264         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
    265         *
    266         * @og.rev 4.3.4.0 (2008/12/01) 新規追加
    267         * @og.rev 6.3.1.1 (2015/07/10) BodyString,BodyRawStringは、CommonTagSupport で、trim() します。
    268         *
    269         * @return      後続処理の指示(SKIP_BODY)
    270         */
    271        @Override
    272        public int doAfterBody() {
    273                bodyStr = getBodyString();
    274                return SKIP_BODY ;
    275        }
    276
    277        /**
    278         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    279         *
    280         * @og.rev 4.1.1.0 (2008/02/22) 新規作成
    281         * @og.rev 4.1.2.0 (2008/03/12) sqlType,execType 判定
    282         * @og.rev 4.2.0.1 (2008/03/27) from を取得
    283         * @og.rev 4.2.1.0 (2008/04/11) ErrMessageManager対応
    284         * @og.rev 4.3.4.0 (2008/12/01) ユニークキーチェック対応。bodyContentの取得を#doAfterBody()で行う。
    285         * @og.rev 5.1.9.0 (2010/08/01) エラーメッセージの表示前後にincludeするJSPを指定できるようにする。
    286         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    287         * @og.rev 5.3.7.0 (2011/07/01) TransactionReal の引数変更 、Transaction対応で、close処理を入れる。
    288         * @og.rev 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
    289         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
    290         *
    291         * @return      後続処理の指示
    292         */
    293        @Override
    294        public int doEndTag() {
    295                debugPrint();
    296                int rtnCode = EVAL_PAGE;
    297
    298                // 4.1.2.0 (2008/03/12) 実行条件 isExec を評価
    299                if( isExec && check( command, COMMAND_SET ) ) {
    300                        // exist="notuse"の場合はチェックしない
    301                        if( "notuse".equalsIgnoreCase( exist ) ) { return rtnCode; }
    302
    303                        // パラメーターから処理のタイプを判別
    304                        checkParam();
    305
    306                        // エラーメッセージを管理するクラスを作成します。
    307                        final ErrMessageManager manager = new ErrMessageManager();
    308                        manager.setTitle( "Data Check Error!" );
    309                        manager.setParamKeys( lblParamKeys );
    310                        manager.setResourceManager( getResource() );
    311                        manager.setFrom( from );
    312
    313                        // 6.3.6.1 (2015/08/28) Transaction でAutoCloseableを使用したtry-with-resources構築に対応。
    314                        try( final Transaction tran = getTransaction() ) {
    315                                // command="NEW"の場合
    316                                if( CMD_NEW.equals( command ) ) {
    317                                        if( isSql ) {
    318                                                checkSql( bodyStr, manager, null, 0, DBTableModel.UPDATE_TYPE, tran );          // 5.1.9.0 (2010/08/01)
    319                                        }
    320                                        else {
    321                                                checkJs( bodyStr, manager, null, 0, jsEngine );
    322                                        }
    323                                }
    324                                // command="ENTRY"の場合(テーブルモデルが存在しない場合は処理しない)
    325                                else if( CMD_ENTRY.equals( command ) ) {
    326                                        table = (DBTableModel) getObject( tableId );
    327                                        if( table != null && table.getRowCount() > 0 ) {
    328                                                manager.setDBTableModel( table );
    329                                                if( isUniqCheck ) {
    330                                                        checkUnique( manager );
    331                                                }
    332                                                else {
    333                                                        checkRows( bodyStr, manager, tran );            // 5.1.9.0 (2010/08/01)
    334                                                }
    335                                        }
    336                                        else {
    337                                                System.out.println( "DBTableModel doesn't exist!! need this when command=\"ENTRY\"" );
    338                                        }
    339                                }
    340                                tran.commit();                          // 6.3.6.1 (2015/08/28)
    341                        }
    342
    343                        // エラーが発生した場合は、エラーメッセージを表示して以降の処理を行わない。
    344                        final ErrorMessage errMessage = manager.getErrMessage() ;
    345                        if( errMessage != null && !errMessage.isOK() && !errRemove ) {
    346                                rtnCode = SKIP_PAGE;
    347
    348                                // 5.1.9.0 (2010/08/01) エラーメッセージの表示前にincludeするJSPを指定
    349                                if( beforeErrorJsp != null && beforeErrorJsp.length() > 0 ) {
    350                                        includeJsp( beforeErrorJsp );
    351                                }
    352
    353//                              jspPrint( TaglibUtil.makeHTMLErrorTable( errMessage, getResource() ) );
    354                                jspPrint( TaglibUtil.makeHTMLErrorTable( errMessage, getResource(),useSLabel ) );               // 7.0.7.0 (2019/12/13)
    355
    356                                // 5.1.9.0 (2010/08/01) エラーメッセージの表示後にincludeするJSPを指定
    357                                if( afterErrorJsp != null && afterErrorJsp.length() > 0 ) {
    358                                        includeJsp( afterErrorJsp );
    359                                }
    360                        }
    361                }
    362
    363                return rtnCode ;
    364        }
    365
    366        /**
    367         * タグリブオブジェクトをリリースします。
    368         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    369         *
    370         * @og.rev 4.1.1.0 (2008/02/22) 新規作成
    371         * @og.rev 4.1.2.0 (2008/03/12) sqlType , execType , isExec 追加
    372         * @og.rev 4.2.0.1 (2008/03/27) conditionKey , conditionList , msgParamKeys 追加
    373         * @og.rev 5.1.9.0 (2010/08/01) beforeErrorJsp , afterErrorJsp, selectedAll 追加
    374         * @og.rev 5.7.6.2 (2014/05/16) where 追加。tableExist タグに伴う便利機能追加
    375         * @og.rev 6.3.4.0 (2015/08/01) isExec は、パラメータではなく、ローカル変数。
    376         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
    377         */
    378        @Override
    379        protected void release2() {
    380                super.release2();
    381                tableId                 = HybsSystem.TBL_MDL_KEY;
    382                dbid                    = null;
    383                command                 = CMD_ENTRY;
    384                table                   = null;
    385                exist                   = "auto";
    386                errRemove               = false;
    387                lbl                     = null;
    388                lblParamKeys    = null;         // 4.2.0.1 (2008/03/27)
    389                isSql                   = false;
    390                isUniqCheck             = false;        // 4.3.4.0 (2008/12/01)
    391                jsEngine                = null;
    392                sqlType                 = null;         // INSERT,COPY,UPDATE,MODIFY,DELETE
    393                execType                = null;         // INSERT,COPY,UPDATE,MODIFY,DELETE
    394                conditionKey    = null;         // 4.2.0.1 (2008/03/27)
    395                conditionList   = null;         // 4.2.0.1 (2008/03/27)
    396                from                    = null;         // 4.2.0.1 (2008/03/27)
    397                where                   = null;         // 5.7.6.2 (2014/05/16) tableExist タグに伴う便利機能追加
    398                bodyStr                 = null;         // 4.3.4.0 (2008/12/01))
    399                uniqCheckClms   = null;         // 4.3.4.0 (2008/12/01)
    400                beforeErrorJsp  = null;         // 5.1.9.0 (2010/08/01)
    401                afterErrorJsp   = null;         // 5.1.9.0 (2010/08/01)
    402                selectedAll             = false;        // 5.1.9.0 (2010/08/01)
    403                useSLabel               = false;        // 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    404        }
    405
    406        /**
    407         * 引数及びボディー部分のチェックを行い、処理のタイプを判別します。
    408         *
    409         * @og.rev 5.5.8.0 (2012/11/01) タイプ判別変更
    410         * @og.rev 5.6.1.1 (2013/02/08) FROM 部の切り出し位置修正
    411         * @og.rev 5.7.6.2 (2014/05/16) tableExist タグに伴う便利機能追加。from属性とwhere属性追加
    412         */
    413        private void checkParam() {
    414                isUniqCheck = uniqCheckClms != null && uniqCheckClms.length > 0 ;
    415                if( isUniqCheck ) {
    416                        if( !CMD_ENTRY.equals( command ) ) {
    417                                final String errMsg = "ユニークキーチェックは、command=\"ENTRY\"の場合のみ使用可能です。"
    418                                                        + " command=" + command ;               // 5.1.8.0 (2010/07/01) errMsg 修正
    419                                throw new HybsSystemException( errMsg );
    420                        }
    421                }
    422                // 5.7.6.2 (2014/05/16) tableExist タグに伴う便利機能追加。from属性とwhere属性追加
    423                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    424                else if( from == null ) {
    425                        if( bodyStr == null || bodyStr.isEmpty() ) {
    426                                final String errMsg = "Body部分にチェック定義を記述して下さい。";
    427                                throw new HybsSystemException( errMsg );
    428                        }
    429
    430                        // SQLチェックかJavaScriptによるチェックかの判定
    431                        final String query = bodyStr.toUpperCase( Locale.JAPAN );               // 4.2.0.1 (2008/03/27)
    432                        if( query.indexOf( "SELECT" ) == 0 ) { // 5.5.8.0 (2012/11/01) 先頭に限定する。(trim済のため)
    433                                isSql = true;
    434                                final int st = query.indexOf( "FROM" ) ;
    435                                final int ed = query.indexOf( "WHERE" ) ;
    436                                if( st > 0 && st < ed ) {
    437                                        from = query.substring( st+"FROM".length(),ed ).trim();         // 5.6.1.1 (2013/02/08)
    438                                }
    439                        }
    440                        else {
    441                                jsEngine = new ScriptEngineManager().getEngineByName( "JavaScript" );
    442                        }
    443                }
    444                else {
    445                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
    446                                .append( "SELECT count(*) FROM " ).append( from );
    447                        if( where != null ) { buf.append( " WHERE " ).append( where ); }
    448                        bodyStr = buf.toString();
    449                        isSql = true;
    450                }
    451        }
    452
    453        /**
    454         * SQLによるデータチェックを行います。
    455         * チェック方法は、exist属性の指定に依存します。
    456         * autoの場合は、テーブルモデルの改廃Cから自動でチェック方法が決定されます。
    457         *
    458         * @param       str             実行するSQL文
    459         * @param       manager ErrMessageManagerオブジェクト
    460         * @param       values  SQL文のパラメータ
    461         * @param       row             行番号
    462         * @param       modifyType      改廃C
    463         * @param       tran    トランザクションオブジェクト
    464         *
    465         * @return      処理の成否
    466         *
    467         * @og.rev 4.1.1.0 (2008/02/22) 新規作成
    468         * @og.rev 4.2.1.0 (2008/04/11) ErrMessageManager対応
    469         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    470         */
    471        private boolean checkSql( final String str, final ErrMessageManager manager, final String[] values
    472                                                        , final int row, final String modifyType, final Transaction tran ) {
    473
    474                final int cnt = DBUtil.dbExist( str, values, tran, dbid );                      // 5.1.9.0 (2010/08/01)
    475
    476                boolean okFlag = true;
    477                String id = null;
    478                if( ( "true".equalsIgnoreCase( exist ) || ( "auto".equalsIgnoreCase( exist )
    479                                && ( DBTableModel.UPDATE_TYPE.equals( modifyType ) || DBTableModel.DELETE_TYPE.equals( modifyType ) ) ) ) && cnt <= 0 ) {
    480                        // ERR0025=データ未登録エラー。キー={0}、値={1} のデータは、存在していません。
    481                        id = ( lbl == null ? "ERR0025" : lbl );
    482                        okFlag = false;
    483                }
    484                else if( ( "false".equalsIgnoreCase( exist ) || ( "auto".equalsIgnoreCase( exist )
    485                                && DBTableModel.INSERT_TYPE.equals( modifyType ) ) ) && cnt > 0 ) {
    486                        // ERR0026=データ登録済みエラー。キー={0}、値={1} のデータは、すでに存在しています。
    487                        id = ( lbl == null ? "ERR0026" : lbl );
    488                        okFlag = false;
    489                }
    490                else if( "one".equalsIgnoreCase( exist ) && cnt > 1 ) {
    491                        // ERR0027=データ２重登録エラー。キー={0}、値={1} のデータは、重複して存在しています。
    492                        id = ( lbl == null ? "ERR0027" : lbl );
    493                        okFlag = false;
    494                }
    495
    496                if( !okFlag ) {
    497                        manager.addMessage( row, id, values );
    498                }
    499                return okFlag;
    500        }
    501
    502        /**
    503         * JavaScriptの式を実行します。
    504         * 実行した結果がboolean型でない場合はエラーとなります。
    505         *
    506         * @param str  実行するSQL文
    507         * @param       manager オブジェクト
    508         * @param values 値配列
    509         * @param row 行番号
    510         * @param engine JavaScriptエンジン
    511         *
    512         * @return 処理の成否
    513         *
    514         * @og.rev 4.1.1.0 (2008/02/22) 新規作成
    515         * @og.rev 4.2.0.1 (2008/03/27) getClass().getName() から、instanceof に変更
    516         * @og.rev 4.2.1.0 (2008/04/11) ErrMessageManager対応
    517         */
    518        private boolean checkJs(  final String str, final ErrMessageManager manager, final String[] values
    519                                                        , final int row, final ScriptEngine engine ) {
    520                // JavaScriptエンジンによる評価
    521                Object obj = null;
    522                try {
    523                        obj = engine.eval( str );
    524                }
    525                catch( final ScriptException ex ) {
    526                        final String errMsg = "JavaScript式のパースに失敗しました。[" + str + "]";
    527                        throw new HybsSystemException( errMsg , ex );
    528                }
    529
    530                // 返り値がBoolean型かチェック
    531                boolean okFlag = false;
    532                // 4.2.0.1 (2008/03/27) instanceof に変更
    533                if( obj instanceof Boolean ) {  // 4.3.1.1 (2008/08/23) instanceof チェックは、nullチェック不要
    534                        okFlag = ((Boolean)obj).booleanValue();
    535                }
    536                else {
    537                        final String errMsg = "JavaScript式には true 若しくは false が返るように設定して下さい"
    538                                                + " Object=" + obj ;                    // 5.1.8.0 (2010/07/01) errMsg 修正
    539                        throw new HybsSystemException( errMsg );
    540                }
    541
    542                if( !okFlag ) {
    543                        // ERR0030=入力したデータが不正です。key={0} value={1} 形式={2}
    544                        final String id = ( lbl == null ? "ERR0030" : lbl );
    545
    546                        manager.addMessage( row, id, values );
    547                }
    548
    549                return okFlag;
    550        }
    551
    552        /**
    553         * DBテーブルモデルの各行に対してデータチェックを行います。
    554         *
    555         * @param str           チェック対象の文字列
    556         * @param manager       ErrMessageManagerオブジェクト
    557         * @param tran          トランザクションオブジェクト
    558         *
    559         * @og.rev 4.1.1.0 (2008/02/22) 新規作成
    560         * @og.rev 4.2.0.1 (2008/03/27) conditionKey,conditionList 対応
    561         * @og.rev 4.2.1.0 (2008/04/11) ErrMessageManager対応
    562         * @og.rev 5.1.9.0 (2010/08/01) Transaction 対応します。
    563         * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいコンストラクターを追加する。
    564         */
    565        private void checkRows( final String str, final ErrMessageManager manager, final Transaction tran ) {
    566
    567                final int[] rowNo = getParameterRows(); // 4.0.0 (2005/01/31)
    568                if( rowNo.length == 0 ) { return; }
    569
    570                final Formatter format = new Formatter( table,str );            // 6.4.3.4 (2016/03/11)
    571                final int[] clmNo = format.getClmNos();
    572                // 4.2.0.1 (2008/03/27) カラム名のメッセージリソース文字列を作成します。
    573                manager.setClmNos( clmNo );
    574
    575                // SQL文の場合のみ[xxx]を?に変換したSQL文を取得(JavaScriptの場合はループ内で各行毎に取得
    576                String query = null;
    577                if( isSql ) {
    578                        query = format.getQueryFormatString();
    579                }
    580
    581                // 4.2.0.1 (2008/03/27) conditionKey,conditionList 対応
    582                int cndKeyNo = -1;
    583                if( conditionKey != null && conditionList != null ) {
    584                        cndKeyNo = table.getColumnNo( conditionKey );           // 不正指定はエラー
    585                }
    586
    587                final List<Integer> list = new ArrayList<>();
    588                boolean okFlag = false;
    589                for( int i=0; i<rowNo.length; i++ ) {
    590                        final int row = rowNo[i] ;
    591                        final String[] values = getTableModelData( row, clmNo );
    592                        // 4.2.0.1 (2008/03/27) 条件指定がされている場合に、
    593                        // Listに含まれない場合は、実行されない。
    594                        // 4.2.1.0 (2008/04/11) 厳密に処理します。
    595                        if( cndKeyNo >= 0 && conditionList.indexOf( table.getValue( row,cndKeyNo ) ) < 0 ) {
    596                                final String conVal = "|" + table.getValue( row,cndKeyNo ) + "|" ;
    597                                if( conditionList.indexOf( conVal ) < 0 ) { continue; }
    598                        }
    599
    600                        if( isSql ) {
    601                                okFlag = checkSql( query, manager, values, row, table.getModifyType( row ), tran );
    602                        }
    603                        else {
    604                                final String jsStr = format.getFormatString( row, "\"" );
    605                                okFlag = checkJs( jsStr, manager, values, row, jsEngine );
    606                        }
    607
    608                        if( errRemove && okFlag ) {
    609                                list.add( row );
    610                        }
    611                }
    612
    613                if( errRemove ) {
    614                        final Integer[] in = list.toArray( new Integer[list.size()] );
    615                        int[] newRowNo = new int[in.length];
    616                        for( int i=0; i<in.length; i++ ) {
    617                                newRowNo[i] = in[i].intValue();
    618                        }
    619                        setParameterRows( newRowNo );
    620                }
    621        }
    622
    623        /**
    624         * DBテーブルモデルの各行にユニークキーのチェックを行います。
    625         *
    626         * @og.rev 4.3.4.0 (2008/12/01) 新規作成
    627         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    628         *
    629         * @param manager ErrMessageManagerオブジェクト
    630         */
    631        private void checkUnique( final ErrMessageManager manager ) {
    632                final int[] rowNo = getParameterRows();
    633                if( rowNo.length == 0 ) { return; }
    634
    635                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    636                if( uniqCheckClms == null ) { return; }
    637
    638                int[] clmNo = new int[uniqCheckClms.length];
    639                for( int i=0; i<clmNo.length; i++ ) {
    640                        clmNo[i] = table.getColumnNo( uniqCheckClms[i] );
    641                }
    642
    643                manager.setClmNos( clmNo );
    644
    645                final List<Integer> list = new ArrayList<>();
    646                final Map<String,Integer> map = new HashMap<>();
    647                for( int i=0; i<rowNo.length; i++ ) {
    648                        final int row = rowNo[i] ;
    649                        final String[] values = getTableModelData( row, clmNo );
    650                        final String key = StringUtil.array2line( values, " + " );
    651
    652                        if( map.get( key ) == null ) {
    653                                map.put( key, 1 );
    654                                if( errRemove ) {
    655                                        list.add( row );
    656                                }
    657                        }
    658                        else {
    659                                // ERR0027=データ２重登録エラー。キー={0}、値={1} のデータは、重複して存在しています。
    660                                id = ( lbl == null ? "ERR0027" : lbl );
    661                                manager.addMessage( row, id, values );
    662                        }
    663                }
    664
    665                if( errRemove ) {
    666                        final Integer[] in = list.toArray( new Integer[list.size()] );
    667                        int[] newRowNo = new int[in.length];
    668                        for( int i=0; i<in.length; i++ ) {
    669                                newRowNo[i] = in[i].intValue();
    670                        }
    671                        setParameterRows( newRowNo );
    672                }
    673        }
    674
    675        /**
    676         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    677         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    678         *
    679         * @og.tag
    680         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
    681         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
    682         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
    683         * この tableId 属性を利用して、メモリ空間を分けます。
    684         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    685         *
    686         * @param       id テーブルID (sessionに登録する時のID)
    687         */
    688        public void setTableId( final String id ) {
    689                tableId = nval( getRequestParameter( id ), tableId );
    690        }
    691
    692        /**
    693         * 【TAG】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します(初期値:null)。
    694         *
    695         * @og.tag Queryオブジェクトを作成する時のDB接続IDを指定します。
    696         *
    697         * @param       id データベース接続ID
    698         */
    699        public void setDbid( final String id ) {
    700                dbid = nval( getRequestParameter( id ), dbid );
    701        }
    702
    703        /**
    704         * 【TAG】コマンド (NEW or ENTRY)をセットします。
    705         *
    706         * @og.tag
    707         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
    708         * フィールド定数値のいづれかを、指定できます。
    709         *
    710         * @param       cmd コマンド (public static final 宣言されている文字列)
    711         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.DataCheckTag.CMD_NEW">コマンド定数</a>
    712         */
    713        public void setCommand( final String cmd ) {
    714                final String cmd2 = getRequestParameter( cmd );
    715                if( cmd2 != null && cmd2.length() > 0 ) {
    716                        command = cmd2.toUpperCase( Locale.JAPAN );
    717                }
    718        }
    719
    720        /**
    721         * 【TAG】データベースのチェック方法[auto/true/false/one/notuse]を指定します(初期値:auto[自動])。
    722         *
    723         * @og.tag
    724         * exist 属性に指定された 、｢true:存在する｣、｢false:存在しない｣、｢one:ひとつ以下｣、
    725         * の値は、いずれの場合も、成立時は、正常とみなします。
    726         * ｢auto:自動｣は、DBTableModeleのmodifyType(A,C,D)に応じて、チェックします。
    727         * A,C,D は、entryタグにコマンドを渡してデータを作成したときに、内部で作成されます。
    728         * (command="NEW"の場合は、trueと同じ動きになります。)
    729         * notuse は、チェックを行いません。これは、このタグを共有使用する場合に、外部で
    730         * チェックを行うかどうかを指定できるようにするために使用します。
    731         * (｢true:存在する｣ には、データが存在した場合に、ＯＫで、なければエラーです。)
    732         * 初期値は、｢auto:自動｣です。
    733         *
    734         * @param       ext チェック方法 [auto:自動/true:存在する/false:存在しない/one:ひとつ以下/notuse:チェックしない]
    735         */
    736        public void setExist( final String ext ) {
    737                exist = nval( getRequestParameter( ext ), exist );
    738                if( !"auto".equalsIgnoreCase( exist )
    739                                && !"true".equalsIgnoreCase( exist )
    740                                && !"false".equalsIgnoreCase( exist )
    741                                && !"one".equalsIgnoreCase( exist )
    742                                && !"notuse".equalsIgnoreCase( exist ) ) {
    743                        final String errMsg = "exist 属性は、(auto,true,false,one,notuse)を指定してください。 [" + exist + "]" + CR;
    744                        throw new HybsSystemException( errMsg );
    745                }
    746        }
    747
    748        /**
    749         * 【TAG】エラー時の選択行を取り除いて継続処理を行うかどうか[true/false]を指定します(初期値:false)。
    750         *
    751         * @og.tag
    752         * exist 属性に指定された 、｢true:存在する｣、｢false:存在しない｣、｢one:ひとつ以下｣、
    753         * に対して、エラーが発生した選択行番号を、取り除いて以下の処理を継続するかどうかを
    754         * 指定します。
    755         * true に設定した場合は、エラーデータを削除し、継続処理を行うことができます。
    756         * flase の場合は、エラーデータを表示して、継続処理を停止します。
    757         * 初期値は、｢false:エラー時停止｣です。
    758         *
    759         * @param       flag ｴﾗｰﾃﾞｰﾀを除外 [true:継続処理/false:エラー時停止]
    760         */
    761        public void setErrRemove( final String flag ) {
    762                errRemove = nval( getRequestParameter( flag ), errRemove );
    763        }
    764
    765        /**
    766         * 【TAG】ラベルリソースのラベルIDを指定します。
    767         *
    768         * @og.tag ラベルリソースIDを指定します。
    769         * 各処理に応じた初期設定のラベルリソースIDは、以下の通りです。
    770         *   exist="true"   ERR0025=データ未登録エラー。キー={0}、値={1} のデータは、存在していません。
    771         *   exist="false"  ERR0026=データ登録済みエラー。キー={0}、値={1} のデータは、すでに存在しています。
    772         *   exist="one"    ERR0027=データ２重登録エラー。キー={0}、値={1} のデータは、重複して存在しています。
    773         *   JavaScript     ERR0030=入力したデータが不正です。key={0} value={1} 形式={2}
    774         * 引数のパラメータには、通常、チェックに使用した実データが、DBTableModel から取得されます。
    775         * 引数を変更する場合は、lblParamKeys を使用してください。
    776         *
    777         * @param id メッセージID
    778         * @see    #setLblParamKeys( String )
    779         */
    780        @Override
    781        public void setLbl( final String id ) {
    782                // 継承親のメソッドを使わない。
    783                lbl = nval( getRequestParameter( id ), lbl );
    784        }
    785
    786        /**
    787         * 【TAG】ラベルリソースの引数をCSV形式で指定します。
    788         *
    789         * @og.tag
    790         * ラベルリソースのキーをCSV形式で指定することで、設定します。
    791         * ラベルに引数( {0},{1} など ) がある場合、ここで指定した値を
    792         * 順番に、{0},{1},{2}・・・ に当てはめていきます。
    793         * キーワードは、CSV形式で指定し、それを分解後、ラベルリソースで
    794         * リソース変換を行います。(つまり、記述された値そのものでは在りません)
    795         * PL/SQL では、"{#PN}" などと指定していた分は、同様に "PN" と指定しです。
    796         * 内部的に、where 条件に指定されたキーと値は、&#064;KEY と &#064;VAL に、
    797         * from と where の間の文字列は、&#064;TBL に対応付けられます。
    798         * {&#064;XXXX} 変数も使用できます。実データの値を取出したい場合は、[PN]と
    799         * すれば、DBTableModel の PN の値を取出します。
    800         * なにも指定しない場合は、キー={0} 、値={1}、from={2} です。
    801         *
    802         * @og.rev 4.2.0.1 (2008/03/27) 新規追加
    803         *
    804         * @param keys メッセージリソースのキー(CSV)
    805         * @see    #setLbl( String )
    806         */
    807        public void setLblParamKeys( final String keys ) {
    808                lblParamKeys = getCSVParameter( keys );
    809        }
    810
    811        /**
    812         * 【TAG】このチェックを行う、SQLタイプ を指定します。
    813         *
    814         * @og.tag
    815         * SQLタイプは、INSERT,COPY,UPDATE,MODIFY,DELETE などの記号を指定します。
    816         * 一般には、result 画面から update 画面へ遷移するときの、command と
    817         * 同じにしておけばよいでしょう。
    818         * これは、execType とマッチした場合のみ、このチェックが処理されます。
    819         * 簡易 equals タグの代役に使用できます。
    820         * なにも指定しない場合は、チェックは実行されます。
    821         *
    822         * @og.rev 4.1.2.0 (2008/03/12) 新規追加
    823         *
    824         * @param       type このチェックを行うSQLタイプ
    825         */
    826        public void setSqlType( final String type ) {
    827                sqlType = nval( getRequestParameter( type ),sqlType );
    828        }
    829
    830        /**
    831         * 【TAG】このチェックを行う、実行タイプ を指定します。
    832         *
    833         * @og.tag
    834         * 実行タイプは、sqlType とマッチした場合のみ、このチェックが処理されます。
    835         * 簡易 equals タグの代役に使用できます。
    836         * execType は、複数指定が可能です。単純な文字列マッチで、sqlType を
    837         * 含めば、実行されます。
    838         * 例えば、sqlType={&#064;sqlType} execType="INSERT|COPY" とすれば、
    839         * sqlType に、INSERT または、COPY が登録された場合にチェックが掛かります。
    840         * なにも指定しない場合は、チェックは実行されます。
    841         *
    842         * @og.rev 4.1.2.0 (2008/03/12) 新規追加
    843         *
    844         * @param       type このチェックを行う実行タイプ
    845         */
    846        public void setExecType( final String type ) {
    847                execType = nval( getRequestParameter( type ),execType );
    848        }
    849
    850        /**
    851         * 【TAG】条件判定するカラムＩＤを指定します(初期値:null)。
    852         *
    853         * @og.tag
    854         * 指定のカラムＩＤの値と、conditionList の値を比較して、
    855         * 存在する場合は、check処理を実行します。
    856         * この処理が有効なのは、command="ENTRY" の場合のみです。
    857         *
    858         * @og.rev 4.2.0.1 (2008/03/27) 新規追加
    859         *
    860         * @param       key カラムＩＤ
    861         * @see         #setConditionList( String )
    862         */
    863        public void setConditionKey( final String key ) {
    864                conditionKey = nval( getRequestParameter( key ),null ) ;
    865        }
    866
    867        /**
    868         * 【TAG】条件判定する値のリストを、"|"で区切って登録します(初期値:無条件)。
    869         *
    870         * @og.tag
    871         * conditionKey とペアで指定します。ここには、カラムの設定値のリストを
    872         * 指定することで、複数条件(ＯＲ結合)での比較を行い、リストにカラム値が
    873         * 存在する場合のみ、check処理を実行します。
    874         * この処理が有効なのは、command="ENTRY" の場合のみです。
    875         * 設定しない場合は、無条件に実行します。
    876         *
    877         * @og.rev 4.2.0.1 (2008/03/27) 新規追加
    878         *
    879         * @param       list 条件判定する値("|"で区切)
    880         * @see         #setConditionKey( String )
    881         */
    882        public void setConditionList( final String list ) {
    883                conditionList = nval( getRequestParameter( list ),null ) ;
    884                if( conditionList != null ) {
    885                        conditionList = "|" + conditionList + "|" ;
    886                }
    887        }
    888
    889        /**
    890         * 【TAG】指定されたキーに従って、メモリ上のテーブルに対してユニークキーチェックを行います。
    891         *
    892         * @og.tag
    893         * ユニークキーチェックを行うキーを指定します。ここで、指定されたキーに対して、
    894         * DBTableModelの値をチェックし、全てのキーに同じ値となっている行が存在すればエラーとなります。
    895         * このチェックは、command="ENTRY"の場合のみ有効です。
    896         * また、このチェックは他のチェック(DB存在チェックなど)と同時に処理することはできません。
    897         * キーが指定され手いる場合は、ボディ部分に記述されている定義は無視されます。
    898         * errRemoveの属性がtrueに指定されている場合、重複行は、DBTableModelの並び順から見て、
    899         * 最初の行のみ処理され、2つめ以降の重複行は無視されます。
    900         * なお、キーはCSV形式(CSV形式)で複数指定が可能です。
    901         *
    902         * @og.rev 4.3.4.0 (2008/12/01) 新規追加
    903         *
    904         * @param       clm チェックキー(CSV形式)
    905         */
    906        public void setUniqCheckClms( final String clm ) {
    907                final String tmp = nval( getRequestParameter( clm ),null );
    908                uniqCheckClms = StringUtil.csv2Array( tmp );
    909        }
    910
    911        /**
    912         * 【TAG】エラーが発生した際に、エラーメッセージの表示前にincludeするJSPを指定します。
    913         *
    914         * @og.tag
    915         * エラーが発生した際に、エラーメッセージの表示前にincludeするJSPを指定します。
    916         * エラーが発生していない場合は、ここで指定されたJSPが処理されることはありません。
    917         * 通常は、戻るリンクなどを指定します。
    918         *
    919         * 指定の方法は、相対パス、絶対パスの両方で指定することができます。
    920         * 但し、絶対パスで指定した場合、その基点は、コンテキストのルートディレクトリになります。
    921         * 例) beforeErrorJsp = "/jsp/common/history_back.jsp"
    922         *
    923         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
    924         *
    925         * @param jsp 表示前にincludeするJSPファイル名
    926         */
    927        public void setBeforeErrorJsp( final String jsp ) {
    928                beforeErrorJsp = nval( getRequestParameter( jsp ),beforeErrorJsp );
    929        }
    930
    931        /**
    932         * 【TAG】エラーが発生した際に、エラーメッセージの表示後にincludeするJSPを指定します。
    933         *
    934         * @og.tag
    935         * エラーが発生した際に、エラーメッセージの表示前にincludeするJSPを指定します。
    936         * エラーが発生していない場合は、ここで指定されたJSPが処理されることはありません。
    937         *
    938         * 指定の方法は、相対パス、絶対パスの両方で指定することができます。
    939         * 但し、絶対パスで指定した場合、その基点は、コンテキストのルートディレクトリになります。
    940         * 例) afterErrorJsp = "/jsp/common/history_back.jsp"
    941         *
    942         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
    943         *
    944         * @param jsp 表示後にincludeするJSPファイル名
    945         */
    946        public void setAfterErrorJsp( final String jsp ) {
    947                afterErrorJsp = nval( getRequestParameter( jsp ),afterErrorJsp );
    948        }
    949
    950        /**
    951         * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
    952         *
    953         * @og.tag
    954         * 全てのデータを選択済みデータとして扱って処理します。
    955         * 全件処理する場合に、(true/false)を指定します。
    956         * 初期値は false です。
    957         *
    958         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
    959         *
    960         * @param  all 選択済み処理可否 [true:全件選択済み/false:通常]
    961         */
    962        public void setSelectedAll( final String all ) {
    963                selectedAll = nval( getRequestParameter( all ),selectedAll );
    964        }
    965
    966        /**
    967         * 【TAG】チェックするデータベース名(from 句)を指定します。
    968         *
    969         * @og.tag
    970         * これは、tableExist タグ廃止に伴う便利機能で、通常、BODYに記述された
    971         * SELECT count(*) from XXXX where XXXXX で、チェックしますが、
    972         * from 属性 と、where 属性を指定する事で、内部で、チェック用のSQL文を
    973         * 作成します。
    974         * from が指定された場合は、BODY は無視されますので、ご注意ください。
    975         *
    976         * @og.rev 5.7.6.2 (2014/05/16) 新規追加
    977         *
    978         * @param  frm チェックするテーブルID
    979         */
    980        public void setFrom( final String frm ) {
    981                from = nval( getRequestParameter( frm ),from );
    982        }
    983
    984        /**
    985         * 【TAG】チェックする検索条件(where句)を指定します。
    986         *
    987         * @og.tag
    988         * これは、tableExist タグ廃止に伴う便利機能で、通常、BODYに記述された
    989         * SELECT count(*) from XXXX where XXXXX で、チェックしますが、
    990         * from 属性 と、where 属性を指定する事で、内部で、チェック用のSQL文を
    991         * 作成します。
    992         * where は、from が指定された場合のみ、有効ですし、where を指定しなければ、
    993         * 全件検索になります。
    994         * tableExist タグと異なるのは、where の指定の仕方で、tableExist タグでは、
    995         * names 属性と、対応する where には、? で記述していましたが、
    996         * dataCheck タグでは、通常の [] でDBTableModelの値を指定します。
    997         *
    998         * @og.rev 5.7.6.2 (2014/05/16) 新規追加
    999         *
    1000         * @param  whr チェックするWHERE条件
    1001         */
    1002        public void setWhere( final String whr ) {
    1003                where = nval( getRequestParameter( whr ),where );
    1004        }
    1005
    1006        /**
    1007         * 【TAG】ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)。
    1008         *
    1009         * @og.tag
    1010         * 通常のｴﾗｰﾒｯｾｰｼﾞは、ﾗﾍﾞﾙ（長）が使われますが、これをﾗﾍﾞﾙ（短）を使いたい場合に、true にセットします。
    1011         * ここでのラベル（短）は、ﾀｸﾞ修飾なしの、ﾗﾍﾞﾙ（短）です。
    1012         * 標準はfalse:利用しない=ﾗﾍﾞﾙ（長）です。
    1013         * true/false以外を指定した場合はfalse扱いとします。
    1014         *
    1015         * ﾗﾍﾞﾙﾘｿｰｽの概要説明があれば表示しますが、useSLabel="true" 時は、概要説明を表示しません。
    1016         *
    1017         * @og.rev 7.0.7.0 (2019/12/13) 新規追加
    1018         *
    1019         * @param prm SLABEL利用 [true:利用する/false:利用しない]
    1020         */
    1021        public void setUseSLabel( final String prm ) {
    1022                useSLabel = nval( getRequestParameter( prm ),useSLabel );
    1023        }
    1024
    1025        /**
    1026         * 指定の行番号の、カラムNo配列(int[])に対応した値の配列を返します。
    1027         *
    1028         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を
    1029         * 処理の対象とします。
    1030         *
    1031         * @og.rev 4.2.0.1 (2008/03/27) row と clm を入れ替えます。(他とあわせます)
    1032         *
    1033         * @param       row   行番号
    1034         * @param       clmNo カラムNo配列(可変長引数)
    1035         *
    1036         * @return      行番号とカラムNo配列に対応した、値の配列
    1037         */
    1038        private String[] getTableModelData( final int row, final int... clmNo ) {
    1039                String[] values = new String[clmNo.length];
    1040                for( int i=0; i<values.length; i++ ) {
    1041                        values[i] = table.getValue( row, clmNo[i] );
    1042                }
    1043                return values;
    1044        }
    1045
    1046        /**
    1047         * エラーメッセージの前後に処理するJSPをインクルードします。
    1048         *
    1049         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
    1050         *
    1051         * @param jsp JSP名
    1052         */
    1053        private void includeJsp( final String jsp ) {
    1054                try {
    1055                        pageContext.include( jsp, false );
    1056                } catch( final IOException ex ) {
    1057                        final String errMsg = jsp + " の include に失敗しました。 ";
    1058                        throw new HybsSystemException( errMsg,ex );
    1059                } catch( final ServletException ex ) {
    1060                        final String errMsg = jsp + " の include に失敗しました。 ";
    1061                        throw new HybsSystemException( errMsg,ex );
    1062                }
    1063        }
    1064
    1065        /**
    1066         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
    1067         *
    1068         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
    1069         *
    1070         * @return      選択行の配列
    1071         * @og.rtnNotNull
    1072         */
    1073        @Override
    1074        protected int[] getParameterRows() {
    1075                final int[] rowNo ;
    1076                if( selectedAll ) {
    1077                        final int rowCnt = table.getRowCount();
    1078                        rowNo = new int[ rowCnt ];
    1079                        for( int i=0; i<rowCnt; i++ ) {
    1080                                rowNo[i] = i;
    1081                        }
    1082                } else {
    1083                        rowNo = super.getParameterRows();
    1084                }
    1085                return rowNo ;
    1086        }
    1087
    1088        /**
    1089         * ErrMessage を管理している メソッド集約型内部クラス
    1090         *
    1091         * 繰返し処理部と、固定部が混在したエラーメッセージで、固定部を先に処理し、
    1092         * 繰返し部は、必要時に処理するようにしました。
    1093         * また、実際にエラーが発生して必要になるまで、実行遅延させます。
    1094         *
    1095         * @og.rev 4.2.1.0 (2008/04/11) 新規追加
    1096         * @og.rev 4.3.0.0 (2008/07/24) クラス宣言をstatic化
    1097         */
    1098        private static final class ErrMessageManager {
    1099                // 引数として初期設定される変数
    1100                private ResourceManager resource;
    1101                private DBTableModel    table   ;
    1102                private String          title           ;
    1103                private String          from            ;
    1104                private String[]        lblKeys         ;
    1105                private int[]           clmNo           ;
    1106
    1107                // 内部引数として処理されたキャッシュ値
    1108                private ErrorMessage errMessage ;
    1109                private String          names           ;
    1110                private String          fromLbl         ;
    1111                private String[]        lblVals         ;
    1112
    1113                private boolean isFirst  = true;                // 初期化されていない=true
    1114
    1115                /**
    1116                 * ErrMessage のタイトルを設定します。
    1117                 *
    1118                 * @param       title   タイトル
    1119                 */
    1120                public void setTitle( final String title ) { this.title = title; }
    1121
    1122                /**
    1123                 * 処理対象のテーブル名を設定します。
    1124                 *
    1125                 * @param       from    テーブル名
    1126                 */
    1127                public void setFrom( final String from ) { this.from = from; }
    1128
    1129                /**
    1130                 * 処理対象のテーブルオブジェクトを設定します。
    1131                 *
    1132                 * @param table DBTableModelオブジェクト
    1133                 */
    1134                public void setDBTableModel( final DBTableModel table ) { this.table = table; }
    1135
    1136                /**
    1137                 * ResourceManagerオブジェクトを設定します。
    1138                 *
    1139                 * @param resource ResourceManagerオブジェクト
    1140                 */
    1141                public void setResourceManager( final ResourceManager resource ) { this.resource = resource; }
    1142
    1143                /**
    1144                 * lblParamKeys 属性の配列を設定します。
    1145                 *
    1146                 * @param       lblKeys 属性の配列(可変長引数)
    1147                 */
    1148                public void setParamKeys( final String... lblKeys ) { this.lblKeys = lblKeys; }
    1149
    1150                /**
    1151                 * カラム名列を設定します。
    1152                 *
    1153                 * @param       clmNo   カラム名配列(可変長引数)
    1154                 */
    1155                public void setClmNos( final int... clmNo ) { this.clmNo = clmNo ; }
    1156
    1157                /**
    1158                 * 初期処理を行います。
    1159                 * エラー処理は、エラー時のみ実行する為、必要のない場合は、処理が不要です。
    1160                 * 最初のエラー出力までは、内部オブジェクトの構築処理を行いません。
    1161                 * ２回目以降は、内部変数にキャッシュされた変換値を利用して、高速化します。
    1162                 *
    1163                 * @og.rev 4.2.3.2 (2008/06/20) from が、null なら、なにもしない。
    1164                 */
    1165                private void firstExecute() {
    1166                        errMessage = new ErrorMessage( title );
    1167
    1168                        // テーブル(from) をキーにラベルリソースから値を取得します。
    1169                        // 4.2.3.2 (2008/06/20) from が、null なら、なにもしない。
    1170                        if( from != null ) {
    1171                                fromLbl  = resource.getLabel( from );
    1172                        }
    1173
    1174                        // カラム番号配列から、カラム名のラベルリソース情報のCSV文字列を作成します。
    1175                        names = getKeysLabel( clmNo );
    1176
    1177                        if( lblKeys != null && lblKeys.length > 0 ) {
    1178                                final int size = lblKeys.length;
    1179                                lblVals = new String[size] ;
    1180
    1181                                for( int i=0; i<size; i++ ) {
    1182                                        final String key = lblKeys[i] ;
    1183                                        if( key != null ) {
    1184                                                if(              "@KEY".equals( key ) ) { lblVals[i] = names;   }
    1185                                                else if( "@TBL".equals( key ) ) { lblVals[i] = fromLbl;}
    1186                                                else if( key.startsWith( "{#" ) && key.endsWith( "}" )  ) {
    1187                                                        lblVals[i] = resource.getLabel( key.substring( 2,key.length()-1 ));
    1188                                                }
    1189                                                else {
    1190                                                        lblVals[i] = key;
    1191                                                }
    1192                                        }
    1193                                }
    1194                        }
    1195                }
    1196
    1197                /**
    1198                 * カラムNo配列(int[])に対応したカラム名のメッセージリソース文字列を返します。
    1199                 *
    1200                 * @param       clmNo カラムNo配列(可変長引数)
    1201                 * @return      カラムNo配列に対応した、カラム名のメッセージリソース
    1202                 * @og.rtnNotNull
    1203                 */
    1204                private String getKeysLabel( final int... clmNo ) {
    1205                        final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    1206                        if( table != null && clmNo.length > 0 ) {
    1207                                String key = table.getColumnName( clmNo[0] );
    1208                                buf.append( resource.getLabel( key ) );
    1209                                for( int i=1; i<clmNo.length; i++ ) {
    1210                                        key = table.getColumnName( clmNo[i] );
    1211                                        buf.append( ',' ).append( resource.getLabel( key ) );           // 6.0.2.5 (2014/10/31) char を append する。
    1212                                }
    1213                        }
    1214
    1215                        return buf.toString();
    1216                }
    1217
    1218                /**
    1219                 * カラム名列を設定します。
    1220                 *
    1221                 * @og.rev 4.3.5.7 (2008/03/22) エラーメッセージの行番号を実際の行番号と一致させる。
    1222                 *
    1223                 * @param       row     カラム名
    1224                 * @param       id      カラム名
    1225                 * @param       values  指定の行に対する値配列(可変長引数)
    1226                 */
    1227                public void addMessage( final int row, final String id, final String... values ) {
    1228                        if( isFirst ) { firstExecute(); isFirst = false; }
    1229
    1230                        final String vals = StringUtil.array2csv( values );
    1231                        if( lblVals == null ) {
    1232                                errMessage.addMessage( row + 1, ErrorMessage.NG, id, names, vals, fromLbl );
    1233                        }
    1234                        else {
    1235                                final int size = lblKeys.length;
    1236                                String[] args = new String[size] ;
    1237
    1238                                for( int i=0; i<size; i++ ) {
    1239                                        final String key = lblVals[i] ;
    1240                                        if( key != null ) {
    1241                                                if(              "@VAL".equals( key ) ) { args[i] = vals; }
    1242                                                else if( StringUtil.startsChar( key,'[' ) && key.endsWith( "]" )  ) {           // 6.4.1.1 (2016/01/16) １文字 String.startsWith
    1243                                                        if( table != null ) {
    1244                                                                args[i] = table.getValue( row,key.substring( 1,key.length()-1 ) );
    1245                                                        }
    1246                                                }
    1247                                                else {
    1248                                                        args[i] = key;
    1249                                                }
    1250                                        }
    1251                                }
    1252                                errMessage.addMessage( row + 1, ErrorMessage.NG, id, args );
    1253                        }
    1254                }
    1255
    1256                /**
    1257                 * ErrorMessageオブジェクトを返します。
    1258                 *
    1259                 * @return ErrorMessageオブジェクト
    1260                 */
    1261                public ErrorMessage getErrMessage() { return errMessage; }
    1262        }
    1263
    1264        /**
    1265         * このオブジェクトの文字列表現を返します。
    1266         * 基本的にデバッグ目的に使用します。
    1267         *
    1268         * @return このクラスの文字列表現
    1269         * @og.rtnNotNull
    1270         */
    1271        @Override
    1272        public String toString() {
    1273                return ToString.title(this.getClass().getName() )
    1274                .println( "VERSION", VERSION )
    1275                .println( "tableId", tableId )
    1276                .println( "dbid", dbid )
    1277                .println( "command", command )
    1278                .println( "exist", exist )
    1279                .println( "lbl", lbl )
    1280                .println( "Other...", getAttributes().getAttribute() ).fixForm().toString();
    1281        }
    1282}