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:存在する」 には、データが存在した場合に、OKで、なければエラーです。)
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"        : 条件判定するカラムIDを指定(初期値は 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】条件判定するカラムIDを指定します
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 DB登録
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=データ2重登録エラー。キー={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=データ2重登録エラー。キー={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:存在する」 には、データが存在した場合に、OKで、なければエラーです。)
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=データ2重登録エラー。キー={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】条件判定するカラムIDを指定します(初期値:null)。
852         *
853         * @og.tag
854         * 指定のカラムIDの値と、conditionList の値を比較して、
855         * 存在する場合は、check処理を実行します。
856         * この処理が有効なのは、command="ENTRY" の場合のみです。
857         *
858         * @og.rev 4.2.0.1 (2008/03/27) 新規追加
859         *
860         * @param       key カラムID
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         * 指定することで、複数条件(OR結合)での比較を行い、リストにカラム値が
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                 * 2回目以降は、内部変数にキャッシュされた変換値を利用して、高速化します。
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) 1文字 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}