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.fukurou.business; 017 018import java.sql.Connection; 019import java.sql.ParameterMetaData; 020import java.sql.PreparedStatement; 021import java.sql.ResultSet; 022import java.sql.ResultSetMetaData; 023import java.sql.SQLException; 024import java.util.Map; 025import java.util.HashMap; // 6.4.3.3 (2016/03/04) not null調査が済むまで、元に戻します。 026import java.util.concurrent.ConcurrentMap; // 6.4.3.3 (2016/03/04) 027import java.util.concurrent.ConcurrentHashMap; // 6.4.3.1 (2016/02/12) refactoring 028import java.util.Locale; 029import java.util.Set; 030import java.util.Arrays; 031 032import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 033import org.opengion.fukurou.db.ConnectionFactory; 034import org.opengion.fukurou.db.DBFunctionName; 035import org.opengion.fukurou.db.DBUtil; 036import org.opengion.fukurou.db.Transaction; 037import org.opengion.fukurou.model.Formatter; 038import org.opengion.fukurou.model.DataModel; // 6.7.9.1 (2017/05/19) 039import org.opengion.fukurou.system.DateSet; // 6.4.2.0 (2016/01/29) 040import org.opengion.fukurou.util.ErrMsg; 041import org.opengion.fukurou.util.ErrorMessage; 042import org.opengion.fukurou.util.HybsLoader; 043import org.opengion.fukurou.util.StringUtil; 044import org.opengion.fukurou.util.SystemParameter; 045import static org.opengion.fukurou.system.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 046import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 047 048/** 049 * 業務ロジックを処理するために必要な共通メソッドの実行を行っている抽象クラスです。 050 * 051 * メインロジックについては、各サブクラスで実装する必要があります。 052 * 053 * @og.rev 5.1.1.0 (2009/12/01) 新規作成 054 * @og.group 業務ロジック 055 * 056 * @version 5.0 057 * @author Hiroki Nakamura 058 * @since JDK1.6, 059 */ 060public abstract class AbstractBizLogic { 061 062 /** エラーメッセージをセットする際に使用します {@value} */ 063 protected static final int OK = ErrorMessage.OK; 064 /** エラーメッセージをセットする際に使用します {@value} */ 065 protected static final int WARNING = ErrorMessage.WARNING; 066 /** エラーメッセージをセットする際に使用します {@value} */ 067 protected static final int NG = ErrorMessage.NG; 068 /** エラーメッセージをセットする際に使用します {@value} */ 069 protected static final int EXCEPTION = ErrorMessage.EXCEPTION; 070 /** エラーメッセージをセットする際に使用します {@value} */ 071 protected static final int ORCL_ERR = ErrorMessage.ORCL_ERR; 072 073 /** 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ {@value} */ 074 private static final int DB_FETCH_SIZE = 1001 ; 075 076 private Connection conn ; 077 private Transaction tran ; // 5.1.9.0 (2010/08/01) シーケンス対応 078 private String dbid ; // 5.1.9.0 (2010/08/01) シーケンス対応 079 /* default */ DBFunctionName dbName ; // 5.1.9.0 (2010/08/01) シーケンス対応 080 private HybsLoader loader ; 081 private String[] keys ; 082 private String[] vals ; 083 /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */ 084 private final Map<String, String> variableMap = new HashMap<>(); // 6.4.3.3 (2016/03/04) not null調査が済むまで、元に戻します。 085 /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */ 086 private final ConcurrentMap<String, Formatter> formatMap = new ConcurrentHashMap<>(); 087 /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。 */ 088 private final ConcurrentMap<String, SystemParameter> sysParamMap = new ConcurrentHashMap<>(); 089 private final ErrorMessage errMsg = new ErrorMessage(); 090 private String bizRtn ; // 5.1.8.0 (2010/07/01) メソッド名と変数名を分ける。 091 private boolean debugFlag ; // 5.1.8.0 (2010/07/01) メソッド名と変数名を分ける。 092 093 private final StringBuilder debugMsg = new StringBuilder( BUFFER_MIDDLE ); 094 private boolean useParamMetaData ; // 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応) 095 096 /** 097 * 配列側テーブルモデル 098 * 099 * 配列型テーブルモデル自体は、protected属性であるため、サブクラスから直接参照することができます。 100 * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの 101 * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。 102 * (この想定がなければ、本来は、package privateにすべきです) 103 * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。 104 * 105 * @og.rev 6.7.9.1 (2017/05/19) protected ArrayTableModel を、private DataModel に変更します。 106 */ 107 private DataModel<String> table ; // 6.7.9.1 (2017/05/19) 108 109 /** 110 * 配列型テーブルモデルの現在の処理行 111 * 112 * 行番号自体は、protected属性であるため、サブクラスから直接参照することができます。 113 * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの 114 * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。 115 * (この想定がなければ、本来は、package privateにすべきです) 116 * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。 117 * 118 * ※ インデックス(row)とは、このArrayTableModel に持つ vals 配列の行のインデックスです。 119 * よって、オリジナルのDBTableModelの行番号ではありません。 120 */ 121 protected int row = -1; 122 123 /** 124 * デフォルトコンストラクター 125 * 126 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 127 */ 128 protected AbstractBizLogic() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 129 130 /** 131 * DBのトランザクションオブジェクトを指定します。 132 * 各実装クラスでは、コネクションのcommit,rollbackは行われません。 133 * (全てのDB処理は、1つのトランザクションとして処理されます。) 134 * このため、commit,rollbackは呼び出し元で行う必要があります。 135 * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。 136 * 137 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 138 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応) 139 * 140 * @param tr トランザクション 141 */ 142 public void setTransaction( final Transaction tr ) { 143 tran = tr; 144 conn = tran.getConnection( dbid ); 145 useParamMetaData = ConnectionFactory.useParameterMetaData( dbid ); // 5.3.8.0 (2011/08/01) 146 } 147 148 /** 149 * 接続先IDを指定します。 150 * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。 151 * 152 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 153 * 154 * @param id 接続先ID 155 */ 156 /* default */ void setDbid( final String id ) { 157 dbid = id; 158 } 159 160 /** 161 * 業務ロジックのクラスをロードするためのクラスローダーをセットします。 162 * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。 163 * 164 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 165 * 166 * @param ldr クラスローダー 167 */ 168 /* default */ void setLoader( final HybsLoader ldr ) { 169 if( loader != null ) { 170 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 171 final String errMsg = "既にクラスローダーがセットされています。" 172 + " OLD:" + loader 173 + " IN :" + ldr ; 174 throw new OgRuntimeException( errMsg ); 175 } 176 loader = ldr; 177 } 178 179 /** 180 * 配列型テーブルモデルをセットします。 181 * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。 182 * 183 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 184 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 185 * 186 * @param tbl 配列型テーブルモデル 187 */ 188 /* default */ void setTable( final DataModel<String> tbl ) { 189 if( table != null ) { 190 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 191 final String errMsg = "既に配列型テーブルモデルがセットされています。" 192 + " OLD:" + table 193 + " IN :" + tbl ; 194 throw new OgRuntimeException( errMsg ); 195 } 196 table = tbl; 197 } 198 199 /** 200 * 配列型テーブルモデルを取得します。 201 * 202 * @og.rev 6.7.9.1 (2017/05/19) 新規追加 203 * 204 * @return 配列型テーブルモデル 205 */ 206 protected DataModel<String> getTable() { 207 return table ; 208 } 209 210 /** 211 * 固定値のキー配列を指定します。 212 * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。 213 * 214 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 215 * 216 * @param ks キー配列(可変長引数) 217 */ 218 /* default */ void setKeys( final String... ks ) { 219 if( keys != null ) { 220 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 221 final String errMsg = "既に固定値配列(キー)がセットされています。" + CR 222 + " KESY =" + Arrays.toString( keys ) + CR 223 + " in keys=" + Arrays.toString( ks ) ; 224 throw new OgRuntimeException( errMsg ); 225 } 226 if( ks != null && ks.length > 0 ) { keys = ks; } // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。 227 } 228 229 /** 230 * 固定値の値配列を指定します。 231 * このメソッドは、1度しかセットすることができません。2回以上呼び出しするとエラーになります。 232 * 233 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 234 * 235 * @param vs 値配列(可変長引数) 236 */ 237 /* default */ void setVals( final String... vs ) { 238 if( vals != null ) { 239 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 240 final String errMsg = "既に固定値配列(値)がセットされています。" + CR 241 + " VALS =" + Arrays.toString( vals ) + CR 242 + " in vals=" + Arrays.toString( vs ) ; 243 throw new OgRuntimeException( errMsg ); 244 } 245 if( vs != null && vs.length > 0 ) { vals = vs; } // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。 246 } 247 248 /** 249 * この処理の実行ユーザーIDを指定します。 250 * 251 * @param id 実行ユーザーID(not null) 252 */ 253 /* default */ void setUserId( final String id ) { 254 variableMap.put( "CON.USERID", id); 255 } 256 257 /** 258 * 親(呼び出し)PGIDを指定します。 259 * 260 * @param id 親PGID 261 */ 262 /* default */ void setParentPgId( final String id ) { 263 variableMap.put( "CON.PGPID", id ); 264 } 265 266 /** 267 * デバッグモードにします。 268 */ 269 /* default */ void setDebug() { 270 debugFlag = true; 271 } 272 273 /** 274 * デバッグメッセージを取得します。 275 * 276 * @return デバッグメッセージ 277 * @og.rtnNotNull 278 */ 279 /* default */ String getDebugMsg() { 280 return debugMsg.toString(); 281 } 282 283 /** 284 * 処理を実行します。 285 * 処理の方法は、main()メソッドにより定義されます。 286 * 実装クラスで発生した全ての例外は、Throwableオブジェクトとしてスローされます。 287 * 呼び出し元では、例外を確実にcatchして、commit,rollbackを行ってください。 288 * 289 * @og.rev 5.1.9.0 (2010/08/01) シーケンス対応 290 * 291 * @return 処理が成功したかどうか 292 * @throws Throwable 実行時の全エラーを上位に転送します。 293 */ 294 /* default */ boolean exec() throws Throwable { 295 dbName = DBFunctionName.getDBName( ConnectionFactory.getDBName( dbid ) ); 296 makeParamMap(); 297 init(); 298 299 return main(); 300 } 301 302 /** 303 * 処理のメインロジックの前処理を記述します。 304 * 305 * このメソッド自体は、protected属性であるため、サブクラスから直接参照することができます。 306 * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの 307 * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。 308 * (この想定がなければ、本来は、package privateにすべきです) 309 * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。 310 */ 311 protected abstract void init(); 312 313 /** 314 * 処理のメインロジックを記述します。 315 * 316 * このメソッド自体は、protected属性であるため、サブクラスから直接参照することができます。 317 * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの 318 * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。 319 * (この想定がなければ、本来は、package privateにすべきです) 320 * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。 321 * 322 * @return 処理が正常終了したか 323 */ 324 protected abstract boolean main(); 325 326 /** 327 * 結果ステータスを返します。 328 * 329 * @return 結果ステータス 330 */ 331 /* default */ int getKekka() { 332 return errMsg.getKekka(); 333 } 334 335 /** 336 * エラーメッセージオブジェクトを返します。 337 * 338 * @return エラーメッセージ 339 */ 340 /* default */ ErrorMessage getErrMsg() { 341 return errMsg; 342 } 343 344 /** 345 * 業務ロジックの戻り値を返します。 346 * 347 * @return 戻り値 348 */ 349 /* default */ String getReturn() { 350 return bizRtn; 351 } 352 353 /** 354 * 業務ロジックを実行するために、テーブルモデルが外部からセットされる必要があるか 355 * を返します。 356 * 必須である場合、その業務ロジックは、子ロジックとして呼び出すことができません。 357 * これは、子ロジック呼び出し時は、テーブルモデルがセットされないためです。 358 * (このクラスは、テーブルモデルが外部から指定されている必要はありません。) 359 * 360 * このメソッド自体は、protected属性であるため、サブクラスから直接参照することができます。 361 * 但し、これは、各業務ロジックで直接参照することを想定したものではなく、BizLogicの 362 * メイン構造を拡張するサブクラスを定義する際に使用することを想定しています。 363 * (この想定がなければ、本来は、package privateにすべきです) 364 * このため、業務ロジックを各実装クラスでは直接参照しないで下さい。 365 * 366 * @return テーブルモデルが外部からセットされる必要があるかどうか(常にfalse) 367 */ 368 protected boolean isRequireTable() { 369 return false; 370 } 371 372 /** 373 * デバッグモードかどうかを返します。 374 * 375 * @return デバッグモードかどうか 376 */ 377 protected final boolean isDebug() { 378 return debugFlag; 379 } 380 381 /** 382 * デバッグメッセージを追加します。 383 * 384 * @param msg 追加するデバッグメッセージ 385 */ 386 protected final void debug( final String msg ) { 387 debugMsg.append( msg ).append( CR ); 388 } 389 390 /** 391 * 指定されたキーの値を返します。 392 * 393 * @param key キー 394 * 395 * @return 変数値 396 */ 397 protected final String var( final String key ) { 398 return variableMap.get( key ); 399 } 400 401 /** 402 * 指定されたキーの値をint型に変換して返します。 403 * 404 * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。 405 * 406 * @param key キー 407 * 408 * @return 変数値 409 */ 410 protected final int vari( final String key ) { 411 return str2int( var( key ) ); // 6.7.9.1 (2017/05/19) 412 } 413 414 /** 415 * 指定されたキーの値をdouble型に変換して返します。 416 * 417 * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。 418 * 419 * @param key キー 420 * 421 * @return 変数値 422 */ 423 protected final double vard( final String key ) { 424 return str2dbl( var( key ) ); // 6.7.9.1 (2017/05/19) 425 } 426 427 /** 428 * パラメーターのキー一覧を配列形式で返します。 429 * このパラメーターは、業務ロジック内でセットされたパラメーターも含まれますのでご注意下さい。 430 * 431 * @return パラメーターのキー配列 432 */ 433 protected final String[] varKeys() { 434 final Set<String> keys = variableMap.keySet(); 435 return keys.toArray( new String[keys.size()] ); 436 } 437 438 /** 439 * 指定されたキーで値を登録します。 440 * パラメーターとしてこの業務ロジックが呼ばれる際の引数となっている場合は、 441 * エラーとなります。 442 * 443 * @og.rev 5.2.1.0 (2010/10/01) チェックのバグを修正 444 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 445 * 446 * @param key キー 447 * @param val 値 448 */ 449 protected final void set( final String key, final String val ) { 450 // 6.0.2.5 (2014/10/31) 素直に、variableMap で、キー有無を判定する。 451 if( variableMap.containsKey( key ) ) { 452 final String errMsg = "すでに登録済みのキーを定義することはできません。" + CR 453 + " key =" + key + CR 454 + " val =" + val + CR 455 + " 元 =" + variableMap.get( key ) ; 456 throw new OgRuntimeException( errMsg ); 457 } 458 variableMap.put( key, val ); 459 } 460 461 /** 462 * 指定されたキーで値を登録します。 463 * パラメーターとしてこの業務ロジックが呼ばれる際の引数となっている場合は、 464 * エラーとなります。 465 * 466 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 467 * 468 * @param key キー 469 * @param val 値 470 */ 471 protected final void set( final String key, final int val ) { 472 set( key, String.valueOf( val ) ); 473 } 474 475 /** 476 * 指定されたキーで値(double型)を登録します。 477 * パラメーターとしてこの業務ロジックが呼ばれる際の引数となっている場合は、 478 * エラーとなります。 479 * 480 * @og.rev 5.1.9.0 (2010/08/01) 新規作成 481 * 482 * @param key キー 483 * @param val 値 484 */ 485 protected final void set( final String key, final double val ) { 486 set( key, String.valueOf( val ) ); 487 } 488 489 /** 490 * 処理中の行の指定されたキー(カラム名)の値を返します。 491 * 492 * @param key キー 493 * 494 * @return 値 495 */ 496 protected final String line( final String key ) { 497 return line( key, row ); 498 } 499 500 /** 501 * メインの配列型テーブルモデルに対して、行を指定して値を取得します。 502 * 指定された行が範囲を超えている場合は、nullを返します。 503 * 504 * @og.rev 5.1.8.0 (2010/07/01) テーブルに存在しないカラム名を指定した場合に、NullPointerExceptionが発生するバグを修正 505 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 506 * 507 * @param key キー 508 * @param rw 行番号(インデックス) 509 * 510 * @return 値 511 */ 512 protected final String line( final String key, final int rw ) { 513 if( table == null ) { 514 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 515 final String errMsg = "配列型テーブルモデルがセットされていないため、#line( String,int )メソッドはできません。" + CR 516 + " line( " + key + "," + rw + " );" + CR ; 517 throw new OgRuntimeException( errMsg ); 518 } 519 // 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 520 521 final int col = table.getColumnNo( key ); 522 523 return col < 0 || rw < 0 || rw >= table.getRowCount() ? null : table.getValue( rw, col ); 524 } 525 526 /** 527 * 処理中の行の指定されたカラム番号の値を返します。 528 * line( String )は、毎回、カラム番号を取得しているため、非効率です。 529 * ただし、一旦カラム名から、カラム番号を取得し、それを使用するのと、 530 * linei(String)や、lined(String) などの直接的なメソッドもないため、 531 * 利用者側でそのあたりの処理を入れる必要があります。 532 * 533 * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。 534 * 535 * @param col カラム番号 536 * @return 値 537 */ 538 protected final String line( final int col ) { 539 return line( col, row ); 540 } 541 542 /** 543 * メインの配列型テーブルモデルに対して、行を指定して値を取得します。 544 * 指定された行が範囲を超えている場合は、nullを返します。 545 * 546 * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。 547 * 548 * @param col カラム番号 549 * @param rw 行番号(インデックス) 550 * @return 値 551 */ 552 protected final String line( final int col, final int rw ) { 553 if( table == null ) { 554 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 555 final String errMsg = "配列型テーブルモデルがセットされていないため、#line( String,int )メソッドはできません。" + CR 556 + " line( " + col + "," + rw + " );" + CR ; 557 throw new OgRuntimeException( errMsg ); 558 } 559 560 return col < 0 || rw < 0 || rw >= table.getRowCount() ? null : table.getValue( rw, col ); 561 } 562 563 /** 564 * 処理中の行の指定されたキー(カラム名)の値をint型に変換して返します。 565 * 566 * @og.rev 6.7.9.0 (2017/04/28) row を使用して、#linei( String,int )を呼びます。 567 * 568 * @param key キー 569 * 570 * @return 値 571 */ 572 protected final int linei( final String key ) { 573 return str2int( line( key, row ) ); // 6.7.9.1 (2017/05/19) 574 } 575 576 /** 577 * メインの配列型テーブルモデルに対して、行を指定して値をint型に変換して返します。 578 * 指定された行が範囲を超えている場合は、nullを返します。 579 * 580 * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。 581 * 582 * @param key キー 583 * @param rw 行番号(インデックス) 584 * 585 * @return 値 586 */ 587 protected final int linei( final String key, final int rw ) { 588 return str2int( line( key, rw ) ); // 6.7.9.1 (2017/05/19) 589 } 590 591 /** 592 * 処理中の行の指定されたキー(カラム名)の値をdouble型に変換して返します。 593 * 594 * @og.rev 6.7.9.0 (2017/04/28) row を使用して、#lined( String,int )を呼びます。 595 * 596 * @param key キー 597 * 598 * @return 値 599 */ 600 protected final double lined( final String key ) { 601 return str2dbl( line( key, row ) ); // 6.7.9.1 (2017/05/19) 602 } 603 604 /** 605 * メインの配列型テーブルモデルに対して、行を指定して値をdouble型に変換して返します。 606 * 指定された行が範囲を超えている場合は、nullを返します。 607 * 608 * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。 609 * 610 * @param key キー 611 * @param rw 行番号(インデックス) 612 * 613 * @return 値 614 */ 615 protected final double lined( final String key, final int rw ) { 616 return str2dbl( line( key, rw ) ); // 6.7.9.1 (2017/05/19) 617 } 618 619 /** 620 * 指定のカラム名引数に相当するデータを2重配列で返します。 621 * 622 * @og.rev 6.8.5.0 (2018/01/09) 新規追加 623 * 624 * @param clmNms 値が参照されるカラム名配列(可変長引数) 625 * 626 * @return 指定された名引数に相当するデータの2重配列 627 * @og.rtnNotNull 628 */ 629 protected String[][] getValues( final String... clmNms ) { 630 return ((ArrayTableModel)table).getValues( clmNms ); 631 } 632 633 /** 634 * 文字列を整数に変換します。 635 * 文字列が、nullか、空文字列の場合は、0 を返します。 636 * 637 * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。 638 * 639 * @param val 入力文字列 640 * @return int値 641 */ 642 protected final int str2int( final String val ) { 643 return val == null || val.isEmpty() ? 0 : Integer.parseInt( val ); 644 } 645 646 /** 647 * 文字列をdoubleに変換します。 648 * 文字列が、nullか、空文字列の場合は、0d を返します。 649 * 650 * @og.rev 6.7.9.1 (2017/05/19) 文字列をdoubleに変換します。 651 * 652 * @param val 入力文字列 653 * @return double値 654 */ 655 protected final double str2dbl( final String val ) { 656 return val == null || val.isEmpty() ? 0d : Double.parseDouble( val ); 657 } 658 659 /** 660 * 文字列配列をdouble配列に変換します。 661 * 文字列が、nullか、空文字列の場合は、長さ0の配列を返します。 662 * 663 * @og.rev 6.8.5.0 (2018/01/09) 新規追加 664 * 665 * @param vals double配列に変換する元の文字列配列 666 * @return 指定された文字列配列に対するdoubleに変換された値配列 667 * @og.rtnNotNull 668 */ 669 protected final double[][] str2dblVals( final String[][] vals ) { 670 if( vals == null || vals.length == 0 || vals[0] == null || vals[0].length == 0 ) { 671 return new double[0][0]; 672 } 673 674 final int rowLen = vals.length; 675 final int colLen = vals[0].length; 676 677 final double[][] dbls = new double[rowLen][colLen]; 678 679 for( int row=0; row<rowLen; row++ ) { 680 for( int col=0; col<colLen; col++ ) { 681 dbls[row][col] = str2dbl( vals[row][col] ); 682 } 683 } 684 685 return dbls; 686 } 687 688 /** 689 * テーブルのカラム名の一覧を配列形式で返します。 690 * 691 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 692 * 693 * @return テーブルのカラム名配列 694 */ 695 protected final String[] lineKeys() { 696 if( table == null ) { 697 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 698 final String errMsg = "配列型テーブルモデルがセットされていないため、#lineKeys()メソッドはできません。" ; 699 throw new OgRuntimeException( errMsg ); 700 } 701 else { 702 return table.getNames(); 703 } 704 } 705 706 /** 707 * テーブルにカラムが存在しているかを返します。 708 * 709 * @og.rev 5.2.0.0 (2010/09/01) 710 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 711 * 712 * @param clm カラム名 713 * 714 * @return 存在している場合true、存在していない場合false 715 */ 716 protected final boolean isLine( final String clm ) { 717 if( table == null ) { 718 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 719 final String errMsg = "配列型テーブルモデルがセットされていないため、#isLine( String )メソッドはできません。" + CR 720 + " isLine( " + clm + " );" + CR ; 721 throw new OgRuntimeException( errMsg ); 722 } 723 return table.getColumnNo( clm ) >= 0 ; 724 } 725 726 /** 727 * 業務ロジックの戻り値をセットします。 728 * 729 * @param rtn 戻り値 730 */ 731 protected final void rtn( final String rtn ) { 732 bizRtn = rtn; 733 } 734 735 /** 736 * 子ロジックを実行します。 737 * 実行する子ロジックの呼び出しは、親クラスと同じソースパス、クラスパスで呼び出しされます。 738 * 子ロジックに渡す引数には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 739 * また、子ロジックの戻り値は、val("SUB_RETURN")で取得することができます。 740 * 741 * @param subLogicName 子ロジック名 742 * @param key キー(CSV形式) 743 * @param val 値(CSV形式) 744 * 745 * @return 処理が正常終了したか 746 */ 747 protected final boolean call( final String subLogicName, final String key, final String val ) { 748 return call( subLogicName, key, val, row, table ); 749 } 750 751 /** 752 * 子ロジックを実行します。 753 * 実行する子ロジックの呼び出しは、親クラスと同じソースパス、クラスパスで呼び出しされます。 754 * 子ロジックに渡す引数には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 755 * この場合の値は、引数で指定された、配列型テーブルモデルの行に対応する値になります。 756 * また、子ロジックの戻り値は、val("RETURN")で取得することができます。 757 * 758 * @og.rev 5.1.9.0 (2010/08/01) シーケンス対応 759 * @og.rev 5.4.1.0 (2011/11/01) 値にカンマが含まれている場合に正しく動作しないバグを修正 760 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 761 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 762 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 763 * 764 * @param subLogicName 子ロジック名 765 * @param key キー(CSV形式) 766 * @param val 値(CSV形式) 767 * @param rw 行番号(インデックス) 768 * @param tbl 配列型テーブルモデル 769 * 770 * @return 処理が正常終了したか 771 */ 772 protected final boolean call( final String subLogicName, final String key, final String val, final int rw, final DataModel<String> tbl ) { 773 // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 774 if( loader == null ) { 775 final String errMsg = "#setLoader(HybsLoader)を先に実行しておいてください。" + CR 776 + " subLogicName =" + subLogicName + CR 777 + " key =" + key + CR 778 + " val =" + val + CR 779 + " ArrayTableModel=" + tbl ; 780 throw new OgRuntimeException( errMsg ); 781 } 782 783 final AbstractBizLogic subLogic = (AbstractBizLogic)loader.newInstance( subLogicName ); 784 785 if( subLogic.isRequireTable() ) { 786 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 787 final String errMsg = "このクラスは、外部からテーブルモデルをセットする必要があるため、子ロジックとして呼び出すことはできません。" + CR 788 + " [クラス名=" + subLogic.getClass().getName() + "]" + CR 789 + " subLogicName =" + subLogicName 790 + " key =[" + key + "]" 791 + " val =[" + val + "]" + CR ; 792 throw new OgRuntimeException( errMsg ); 793 } 794 795 subLogic.setTransaction( tran ); 796 subLogic.setLoader( loader ); 797 subLogic.setKeys( StringUtil.csv2Array( key ) ); 798 // 5.4.1.0 (2011/11/01) 値にカンマが含まれている場合に正しく動作しないバグを修正 799 String[] vals = StringUtil.csv2Array( val ); 800 for( int i=0; i<vals.length; i++ ) { 801 vals[i] = replaceParam( vals[i], rw, tbl ); 802 } 803 subLogic.setVals( vals ); 804 subLogic.setUserId( variableMap.get( "CON.USERID" ) ); 805 subLogic.setParentPgId( variableMap.get( "CON.PGID" ) ); 806 if( debugFlag ) { 807 subLogic.setDebug(); 808 } 809 810 final boolean rtn; // 6.3.9.0 (2015/11/06) Found 'DU'-anomaly for variable(PMD) 811 try { 812 rtn = subLogic.exec(); 813 } 814 catch( final Throwable th ) { 815 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 816 final String errMsg = "子ロジックの呼び出しでエラーが発生しました。" + CR 817 + " subLogicName =" + subLogicName + CR 818 + " key =[" + key + "]" 819 + " val =[" + val + "]" + CR ; 820 throw new OgRuntimeException( errMsg ,th ); 821 } 822 variableMap.put( "RETURN", subLogic.getReturn() ); 823 824 if( debugFlag ) { debug( subLogic.getDebugMsg() ); } 825 826 final ErrMsg[] errs = subLogic.getErrMsg().toArray(); 827 if( errs.length > 0 ) { 828 final ErrorMessage errMsgTmp = new ErrorMessage(); 829 for( int i=0; i<errs.length; i++ ) { 830 errMsgTmp.addMessage( errs[i].copy( rw ) ); 831 } 832 errMsg.append( errMsgTmp ); 833 } 834 835 return rtn; 836 } 837 838 /** 839 * SQLを実行します。 840 * SQL文には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 841 * select文を発行した場合、その結果セットは、var(カラム名)で取得することができます。 842 * 2行以上が返された場合でも、1行目のみが登録されます。 843 * また、検索件数、更新件数については、var("SQL_ROWCOUNT")で取得することができます。 844 * 845 * @param sq SQL文字列 846 */ 847 protected final void sql( final String sq ) { 848 sql( sq, row, table ); 849 } 850 851 /** 852 * SQLを実行します。 853 * SQL文には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 854 * [XXXX]形式の変数の置き換えには、引数で指定された配列型テーブルモデルの行が使用されます。 855 * select文を発行した場合、その結果セットは、var(カラム名)で取得することができます。 856 * 2行以上が返された場合でも、1行目のみが登録されます。 857 * また、検索件数、更新件数については、var("SQL_ROWCOUNT")で取得することができます。 858 * 859 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 860 * 861 * @param sq SQL文字列 862 * @param rw 行番号(インデックス) 863 * @param tbl 配列型テーブルモデル 864 */ 865 protected final void sql( final String sq, final int rw, final DataModel<String> tbl ) { 866 final DataModel<String> tbl2 = execSQL( sq, rw, tbl ); 867 868 if( tbl2 != null && tbl2.getRowCount() > 0 ) { 869 final String[] names = tbl2.getNames(); 870 final String[] vals = tbl2.getValues( 0 ); 871 for( int i=0; i<names.length; i++ ) { 872 variableMap.put( names[i], vals[i] ); 873 } 874 } 875 } 876 877 /** 878 * シーケンス名よりシーケンスオブジェクトを検索し、次の値を取り出します。 879 * DBに対するシーケンスオブジェクトは予め作成されている必要があります。 880 * 881 * また、MySQLの場合は、シーケンスオブジェクトが実装されていないため、 882 * 内部的には、引数のシーケンス名と同じ名前のテーブルから、Integer型の 883 * "SEQID"という項目名を検索することにより、シーケンスをエミュレートしています。 884 * 885 * @og.rev 5.1.9.0 (2010/08/01) 新規追加 886 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 887 * 888 * @param seqName シーケンス名 889 * 890 * @return シーケンス番号 891 * @see org.opengion.fukurou.db.DBFunctionName#getSequence(String,Transaction) 892 */ 893 protected final int seq( final String seqName ) { 894 // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 895 if( dbName == null ) { 896 final String errMsg = "#exec()を先に実行しておいてください。" + CR 897 + " seqName =" + seqName ; 898 throw new OgRuntimeException( errMsg ); 899 } 900 901 return dbName.getSequence( seqName, tran ); 902 } 903 904 /** 905 * SQLを実行します。 906 * 907 * @param sq SQL文字列 908 * @param rw 行番号(インデックス) 909 * @param tbl 配列型テーブルモデル 910 * 911 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 912 * 913 * @return 結果セット(配列型テーブルモデル) 914 * 915 * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応) 916 * @og.rev 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&バグ修正) 917 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応 918 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 919 * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。 920 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 921 * @og.rev 6.9.3.0 (2018/03/26) ミス修正(検索件数のところを、フェッチ件数を取得していた) 922 * @og.rev 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズを設定。 923 */ 924 private DataModel<String> execSQL( final String sq, final int rw, final DataModel<String> tbl ) { 925 // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs) 926 if( conn == null ) { 927 final String errMsg = "#setTransaction(Transaction)を先に実行しておいてください。" + CR 928 + " sql =" + sq + CR 929 + " ArrayTableModel=" + tbl ; 930 throw new OgRuntimeException( errMsg ); 931 } 932 933 String sql = replaceParam( sq, false ); // [XXXX]の変換はここでは行わない。 934 Formatter format = null ; 935 if( tbl != null && sql.indexOf( '[' ) >= 0 ) { 936 format = getFormatter( sql, tbl ); 937 sql = format.getQueryFormatString(); 938 } 939 940 DataModel<String> tbl2 = null; 941 // 6.4.2.1 (2016/02/05) try-with-resources 文 942 try( final PreparedStatement pstmt = conn.prepareStatement( sql ) ) { 943 if( tbl != null && format != null ) { 944 final int[] clmNo = format.getClmNos(); 945 946 // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応) 947 if( useParamMetaData ) { 948 final ParameterMetaData pMeta = pstmt.getParameterMetaData(); 949 for( int i=0; i<clmNo.length; i++ ) { 950 final int type = pMeta.getParameterType( i+1 ); 951 // 5.3.8.0 (2011/08/01) setNull 対応 952 final String val = tbl.getValue( rw, clmNo[i] ); 953 if( val == null || val.isEmpty() ) { 954 pstmt.setNull( i+1, type ); 955 } 956 else { 957 pstmt.setObject( i+1, val, type ); 958 } 959 } 960 } 961 else { 962 for( int i=0; i<clmNo.length; i++ ) { 963 pstmt.setObject( i+1, tbl.getValue( rw, clmNo[i] ) ); 964 } 965 } 966 } 967 final boolean status = pstmt.execute(); 968 // 6.4.2.1 (2016/02/05) try-with-resources 文 969 try( final ResultSet result = pstmt.getResultSet() ) { 970 if( status ) { 971 result.setFetchSize( DB_FETCH_SIZE ); // 6.9.3.0 (2018/03/26) データ検索時のフェッチサイズ 972 973 final ResultSetMetaData metaData = result.getMetaData(); 974 final int cols = metaData.getColumnCount(); 975 976 String[] names = new String[cols]; 977 for( int i=0; i<cols; i++ ) { 978 // 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&バグ修正) 979 names[i] = metaData.getColumnLabel( i+1 ).toUpperCase( Locale.JAPAN ); 980 } 981 982 final String[][] tblVals = DBUtil.resultToArray( result, false ); 983 tbl2 = new ArrayTableModel( names, tblVals ); 984 985// variableMap.put( "SQL_ROWCOUNT", String.valueOf( pstmt.getFetchSize() ) ); 986 variableMap.put( "SQL_ROWCOUNT", String.valueOf( tbl2.getRowCount() ) ); // 6.9.3.0 (2018/03/26) ミス修正 987 } 988 else { 989 variableMap.put( "SQL_ROWCOUNT", String.valueOf( pstmt.getUpdateCount() ) ); 990 } 991 } 992 } 993 catch( final SQLException ex ) { // catch は、close() されてから呼ばれます。 994 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 995 final String errMsg = "配列型テーブルモデルの生成に失敗しました。" + CR 996 + " sql =" + sql + CR 997 + " ArrayTableModel=" + tbl ; 998 throw new OgRuntimeException( errMsg,ex ); 999 } 1000 return tbl2; 1001 } 1002 1003 /** 1004 * エラーメッセージを追加します。 1005 * エラーメッセージの引数には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 1006 * 1007 * @param kekka エラーレベル 1008 * @param id エラーメッセージID 1009 * @param args エラーメッセージパラメーター 1010 */ 1011 protected final void error( final int kekka, final String id, final String... args ) { 1012 error( row, kekka, id, args ); 1013 } 1014 1015 /** 1016 * 行指定でエラーメッセージを追加します。 1017 * エラーメッセージの引数には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 1018 * 1019 * @param rw 行番号(インデックス) 1020 * @param kekka エラーレベル 1021 * @param id エラーメッセージID 1022 * @param args エラーメッセージパラメーター 1023 */ 1024 protected final void error( final int rw, final int kekka, final String id, final String... args ) { 1025 errMsg.addMessage( rw, kekka, id, replaceParam( args ) ); 1026 } 1027 1028 /** 1029 * パラメーターの必須チェックを行います。 1030 * キーは、CSV形式で複数指定することができます。 1031 * 1032 * @param cs カラム(CSV形式) 1033 * 1034 * @return エラーが発生した場合はfalse、それ以外はtrue 1035 */ 1036 protected final boolean must( final String cs ) { 1037 if( cs == null || cs.isEmpty() ) { 1038 return true; 1039 } 1040 1041 final String[] clms = StringUtil.csv2Array( cs ); 1042 for( int i=0; i<clms.length; i++ ) { 1043 final String val = variableMap.get( clms[i] ); 1044 if( val == null || val.isEmpty() ) { 1045 error( 2, "ERR0012", "{#" + clms[i] + "}" ); 1046 return false ; 1047 } 1048 } 1049 return true; 1050 } 1051 1052 /** 1053 * マスタチェックを行います。 1054 * 1055 * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加 1056 * 1057 * @see #exist(String, String, String, String, String, String) 1058 * @param type エラーチェックのタイプ 1059 * @param tblId テーブル名 1060 * @param ns カラム(CSV形式) 1061 * @param vs 値(CSV形式) 1062 * 1063 * @return エラーが発生した場合はfalse、それ以外はtrue 1064 */ 1065 protected final boolean exist( final String type, final String tblId, final String ns, final String vs ) { 1066 return exist( type, tblId, ns, vs, null, null,true ); 1067 } 1068 1069 /** 1070 * マスタチェックを行います。 1071 * 1072 * 引数に指定されたテーブル名、及び条件句を生成するためのカラム、値から 1073 * 件数を取得し、typeに応じて件数チェックを行います。 1074 * (カラム、値には、CSV形式で複数指定することができます) 1075 * type=true 存在する場合true 存在しない場合false 1076 * type=false 存在する場合false 存在しない場合true 1077 * type=one 1件以内 true 2件以上 false 1078 * 1079 * 必須チェックの引数には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 1080 * 1081 * また、固定値カラム、値にも条件となるカラム及び値を指定することができますが、 1082 * ここで指定されたカラムは、エラーメッセージ表示時にカラム、値が画面に表示されません。 1083 * 1084 * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加 1085 * 1086 * @param type エラーチェックのタイプ 1087 * @param tblId テーブル名 1088 * @param ns カラム(CSV形式) 1089 * @param vs 値(CSV形式) 1090 * @param conNs 固定値カラム(CSV形式) 1091 * @param conVs 固定値(CSV形式) 1092 * 1093 * @return エラーが発生した場合はfalse、それ以外はtrue 1094 */ 1095 protected final boolean exist( final String type, final String tblId 1096 , final String ns, final String vs, final String conNs, final String conVs ) { 1097 return exist( type, tblId, ns, vs, conNs, conVs,true ); 1098 } 1099 1100 /** 1101 * マスタチェックを行います。 1102 * 引数に指定されたテーブル名、及び条件句を生成するためのカラム、値から 1103 * 件数を取得し、typeに応じて件数チェックを行います。 1104 * (カラム、値には、CSV形式で複数指定することができます) 1105 * type=true 存在する場合true 存在しない場合false 1106 * type=false 存在する場合false 存在しない場合true 1107 * type=one 1件以内 true 2件以上 false 1108 * 1109 * 必須チェックの引数には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 1110 * 1111 * また、固定値カラム、値にも条件となるカラム及び値を指定することができますが、 1112 * ここで指定されたカラムは、エラーメッセージ表示時にカラム、値が画面に表示されません。 1113 * 1114 * isErrThrow は、エラーが発生した場合に、エラーメッセージ(ErrorMessage)に書き込むかどうかを指定します。 1115 * 基本は、互換性を考慮し、true(書き込む)です。 1116 * false にするケースは、存在チェックを行い、あれば更新、なければ追加 など後続処理を行いたい場合に使います。 1117 * 1118 * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加 1119 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 1120 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 1121 * 1122 * @param type エラーチェックのタイプ 1123 * @param tblId テーブル名 1124 * @param ns カラム(CSV形式) 1125 * @param vs 値(CSV形式) 1126 * @param conNs 固定値カラム(CSV形式) 1127 * @param conVs 固定値(CSV形式) 1128 * @param isErrThrow 判定結果がfalseの場合に、error関数を呼ぶ場合は、true。呼ばない場合は、falseをセットします。 1129 * 1130 * @return エラーが発生した場合はfalse、それ以外はtrue 1131 */ 1132 protected final boolean exist( final String type, final String tblId 1133 , final String ns, final String vs, final String conNs, final String conVs, final boolean isErrThrow ) { 1134 if( ns == null || ns.isEmpty() || vs == null || vs.isEmpty() ) { 1135 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 1136 final String errMsg = "カラム又は、値にnullは指定できません。" + CR 1137 + " ns =[" + ns + "]" 1138 + " vs =[" + vs + "]" ; 1139 throw new OgRuntimeException( errMsg ); 1140 } 1141 1142 final String namesStr = ns + ( conNs == null || conNs.isEmpty() ? "" : "," + conNs ); 1143 final String[] namesArr = StringUtil.csv2Array( namesStr ); 1144 final String valsStr = vs + ( conVs == null || conVs.isEmpty() ? "" : "," + conVs ); 1145 final String[] valsArr = StringUtil.csv2Array( valsStr ); 1146 if( namesArr.length != valsArr.length ) { 1147 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 1148 final String errMsg = "カラムと値の個数が異なります。" + CR 1149 + " names = [" + namesStr + "]" + CR 1150 + " vals = [" + valsStr + "]"; 1151 throw new OgRuntimeException( errMsg ); 1152 } 1153 1154 final StringBuilder sb = new StringBuilder( BUFFER_MIDDLE ); 1155 sb.append( "select count(*) CNT from " ).append( tblId ); 1156 for( int i=0 ;i<namesArr.length; i++ ) { 1157 if( i==0 ) { sb.append( " where " ); } 1158 else { sb.append( " and " ); } 1159 sb.append( namesArr[i] ).append( " = " ).append( valsArr[i] ); 1160 } 1161 1162 int count = 0; 1163 final DataModel<String> tbl2 = execSQL( sb.toString(), row, table ); // 6.7.9.1 (2017/05/19) 1164 if( tbl2 != null && tbl2.getRowCount() >= 0 ) { 1165 count = Integer.parseInt( tbl2.getValues( 0 )[0] ); // 6.0.2.4 (2014/10/17) メソッド間違い 1166 } 1167 1168 final String repVals = replaceParam( vs ); 1169 if( "true".equalsIgnoreCase( type ) ) { 1170 // ERR0025=データ未登録エラー。キー={0}、値={1} のデータは、存在していません。 1171 if( count <= 0 ) { 1172 if( isErrThrow ) { error( NG, "ERR0025", "{#" + ns + "}", repVals ); } // 5.6.3.1 (2013/04/05) 1173 return false; 1174 } 1175 } 1176 else if( "false".equalsIgnoreCase( type ) ) { 1177 // ERR0026=データ登録済みエラー。キー={0}、値={1} のデータは、すでに存在しています。 1178 if( count > 0 ) { 1179 if( isErrThrow ) { error( NG, "ERR0026", "{#" + ns + "}", repVals ); } // 5.6.3.1 (2013/04/05) 1180 return false; 1181 } 1182 } 1183 else if( "one".equalsIgnoreCase( type ) ) { 1184 // ERR0027=データ2重登録エラー。キー={0}、値={1} のデータは、重複して存在しています。 1185 if( count > 1 ) { 1186 if( isErrThrow ) { error( NG, "ERR0027", "{#" + ns + "}", repVals ); } // 5.6.3.1 (2013/04/05) 1187 return false; 1188 } 1189 } 1190 else { 1191 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 1192 final String errMsg = "typeは、true、false、oneのいずれかで指定する必要があります。" + CR 1193 + " type = [" + type + "]"; 1194 throw new OgRuntimeException( errMsg ); 1195 } 1196 return true; 1197 } 1198 1199 /** 1200 * 引数に指定されたキー、値をマップ形式に変換します。 1201 * 1202 * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。 1203 * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 1204 */ 1205 private void makeParamMap() { 1206 if( keys != null && vals != null ) { 1207 if( keys.length == vals.length ) { 1208 for( int i=0; i<keys.length; i++ ) { 1209 variableMap.put( keys[i], vals[i] ); 1210 } 1211 } 1212 else { 1213 // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にセットします。 1214 final String errMsg = "keysとvalsの個数が異なります。" + CR 1215 + " keys =" + Arrays.toString( keys ) + CR 1216 + " vals =" + Arrays.toString( vals ) ; 1217 throw new OgRuntimeException( errMsg ); 1218 } 1219 } 1220 1221 final String ymdh = DateSet.getDate( "yyyyMMddHHmmss" ); // 5.5.7.2 (2012/10/09) HybsDateUtil を利用 1222 variableMap.put( "CON.YMDH", ymdh ); 1223 variableMap.put( "CON.YMD", ymdh.substring( 0,8 ) ); 1224 variableMap.put( "CON.HMS", ymdh.substring( 8 ) ); 1225 1226 variableMap.put( "CON.PGID", this.getClass().getSimpleName() ); 1227 } 1228 1229 /** 1230 * {@XXXX}形式及び[XXXX]形式の文字列配列の置き換えを行います。 1231 * 1232 * @og.rev 6.2.2.0 (2015/03/27) #replaceParam( String[] , int , ArrayTableModel ) 廃止に伴う処置 1233 * 1234 * @param str 置き換え対象の配列 1235 * 1236 * @return 置き換え結果の文字列 1237 */ 1238 private String[] replaceParam( final String[] str ) { 1239 for( int i=0; i<str.length; i++ ) { 1240 str[i] = replaceParam( str[i], row, table ); 1241 } 1242 return str; 1243 } 1244 1245 /** 1246 * {@XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。 1247 * 1248 * @param str 置き換え対象の文字列 1249 * 1250 * @return 置き換え結果の文字列 1251 */ 1252 private String replaceParam( final String str ) { 1253 return replaceParam( str, row, table ); 1254 } 1255 1256 /** 1257 * {@XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。 1258 * isRepTableにfalseを指定した場合、Formatterによる[XXXX]変換は行われません。 1259 * (SQLの変換の場合は、PreparedStatementで処理させるため、[XXXX]の変換は行わない。) 1260 * 1261 * @param str 置き換え対象の文字列 1262 * @param isRepTable Formatterによる[XXXX]変換を行うか 1263 * 1264 * @return 置き換え結果の文字列 1265 */ 1266 private String replaceParam( final String str, final boolean isRepTable ) { 1267 return isRepTable ? replaceParam( str, row, table) : replaceParam( str, 0, null ) ; 1268 } 1269 1270 /** 1271 * {@XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。 1272 * [XXXX]形式の置き換えには、引数で指定された配列型テーブルモデル、行番号(インデックス)を使用します。 1273 * 1274 * @og.rev 5.1.8.0 (2010/07/01) 引数チェック漏れ対応 1275 * @og.rev 5.3.9.0 (2011/09/01) nullが連続する場合にゼロストリングに置き換えられないバグを修正 1276 * @og.rev 6.4.3.2 (2016/02/19) Formatterを、値が null の場合は、ゼロ文字列を設定する。 1277 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 1278 * 1279 * @param str 置き換え対象の文字列 1280 * @param rw 行番号(インデックス) 1281 * @param tbl 配列型テーブルモデル 1282 * 1283 * @return 置き換え結果の文字列 1284 */ 1285 private String replaceParam( final String str, final int rw, final DataModel<String> tbl ) { 1286 // 5.1.8.0 (2010/07/01) 引数チェック漏れ対応 1287 if( str == null || str.isEmpty() ) { return ""; } 1288 1289 String rtn = str; 1290 1291 // {@XXXX}の変換 1292 if( !variableMap.isEmpty() && rtn.indexOf( "{@" ) >= 0 ) { // 6.1.1.0 (2015/01/17) refactoring 1293 final SystemParameter sysParam = getSysParam( rtn ); 1294 rtn = sysParam.replace( variableMap ); 1295 } 1296 1297 // [XXXX]の変換 1298 if( tbl != null && rtn.indexOf( '[' ) >= 0 ) { 1299 final Formatter format = getFormatter( rtn, tbl ); 1300 rtn = format.getFormatString( rw ); 1301 } 1302 1303 return rtn; 1304 } 1305 1306 /** 1307 * [XXXX]変換を行うためのFormatterを取得します。 1308 * 1309 * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいコンストラクターを追加する。 1310 * @og.rev 6.4.3.4 (2016/03/11) Map#computeIfAbsent で対応する。 1311 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 1312 * 1313 * @param str 変換文字列 1314 * @param tbl 配列型テーブルモデル 1315 * 1316 * @return Formatterオブジェクト 1317 */ 1318 private Formatter getFormatter( final String str, final DataModel<String> tbl ) { 1319 // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし 1320 final String key = str + tbl.toString(); 1321 return formatMap.computeIfAbsent( key , k -> new Formatter( tbl,str ) ); 1322 1323 } 1324 1325 /** 1326 * {@XXXX}変換を行うためのSystemParameterオブジェクトを取得します。 1327 * 1328 * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のチェック追加 1329 * 1330 * @param str 変換文字列 1331 * 1332 * @return SystemParameterオブジェクト 1333 */ 1334 private SystemParameter getSysParam( final String str ) { 1335 // 6.4.3.3 (2016/03/04) キーが null のときも、SystemParameter オブジェクトを構築しているので、 1336 // それも合わせて、Mapで管理するようにします。 1337 final String key = str == null ? "NULL" : str ; 1338 // Map#computeIfAbsent : 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし 1339 return sysParamMap.computeIfAbsent( key , k -> new SystemParameter( k ) ); 1340 } 1341 1342 /** 1343 * 検索SQLを実行し、結果を配列型テーブルモデルとして返します。 1344 * SQL文には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 1345 * また、検索件数については、var("SQL_ROWCOUNT")で取得することができます。 1346 * 1347 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 1348 * 1349 * @param sq SQL文 1350 * 1351 * @return 配列型テーブルモデル 1352 */ 1353 protected final DataModel<String> createTableBySql( final String sq ) { 1354 return createTableBySql( sq, row, table ); 1355 } 1356 1357 /** 1358 * 検索SQLを実行し、結果を配列型テーブルモデルとして返します。 1359 * SQL文には、{@XXXX}形式及び[XXXX]形式の変数を使用することができます。 1360 * [XXXX]形式の変数の置き換えには、引数で指定された配列型テーブルモデルの行が使用されます。 1361 * また、検索件数については、var("SQL_ROWCOUNT")で取得することができます。 1362 * 1363 * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。 1364 * 1365 * @param sq SQL文 1366 * @param rw 行番号(インデックス) 1367 * @param tbl 配列型テーブルモデル 1368 * 1369 * @return 配列型テーブルモデル 1370 */ 1371 protected final DataModel<String> createTableBySql( final String sq, final int rw, final DataModel<String> tbl ) { 1372 return execSQL( sq, rw, tbl ); 1373 } 1374}