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