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