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