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