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