    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 final String mapGet( final String key ) {
    433                if( key == null ) { return null; }
    434                else {
    435                        return variableMap.get( key.toUpperCase(Locale.JAPAN) );
    436                }
    437        }
    438
    439        /**
    440         * 指定されたｷｰの値を返します。
    441         *
    442         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
    443         *
    444         * @param       key     ｷｰ
    445         *
    446         * @return      変数値
    447         */
    448        protected final String var( final String key ) {
    449//              return variableMap.get( key );
    450                return mapGet( key );
    451        }
    452
    453        /**
    454         * 指定されたｷｰの値を返します。
    455         *
    456         * 値が、nullや空文字列の場合は、def引数の初期値を返します。
    457         *
    458         * @og.rev 8.0.2.0 (2021/11/30) 新規追加
    459         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
    460         *
    461         * @param       key     ｷｰ
    462         * @param       def     値が取得できなかった時の初期値
    463         *
    464         * @return      変数値
    465         */
    466        protected final String var( final String key,final String def ) {
    467                // Map#getOrDefault( key,def ) ではなく、nval を使います。
    468//              return StringUtil.nval( variableMap.get( key ) , def );
    469                return StringUtil.nval( mapGet( key ) , def );
    470        }
    471
    472        /**
    473         * 指定されたｷｰの値をint型に変換して返します。
    474         *
    475         * 値が、nullや空文字列の場合は、def引数の初期値を返します。
    476         *
    477         * @og.rev 8.0.2.0 (2021/11/30) 新規追加
    478         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
    479         *
    480         * @param       key     ｷｰ
    481         * @param       def     値が取得できなかった時の初期値
    482         *
    483         * @return      変数値
    484         */
    485        protected final int var( final String key,final int def ) {
    486                // Map#getOrDefault( key,def ) ではなく、nval を使います。
    487//              return StringUtil.nval( variableMap.get( key ) , def );
    488                return StringUtil.nval( mapGet( key ) , def );
    489        }
    490
    491        /**
    492         * 指定されたｷｰの値をdouble型に変換して返します。
    493         *
    494         * 値が、nullや空文字列の場合は、def引数の初期値を返します。
    495         *
    496         * @og.rev 8.0.2.0 (2021/11/30) 新規追加
    497         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
    498         *
    499         * @param       key     ｷｰ
    500         * @param       def     値が取得できなかった時の初期値
    501         *
    502         * @return      変数値
    503         */
    504        protected final double var( final String key,final double def ) {
    505                // Map#getOrDefault( key,def ) ではなく、nval を使います。
    506//              return StringUtil.nval( variableMap.get( key ) , def );
    507                return StringUtil.nval( mapGet( key ) , def );
    508        }
    509
    510//      /**
    511//       * 指定されたｷｰの値をint型に変換して返します。
    512//       *
    513//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
    514//       * @og.rev 8.0.2.0 (2021/11/30) 廃止 vari(String) → var(String,int)
    515//       *
    516//       * @param       key     ｷｰ
    517//       *
    518//       * @return      変数値
    519//       */
    520//      protected final int vari( final String key ) {
    521//              return str2int( var( key ) );                   // 6.7.9.1 (2017/05/19)
    522//      }
    523
    524//      /**
    525//       * 指定されたｷｰの値をdouble型に変換して返します。
    526//       *
    527//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
    528//       * @og.rev 8.0.2.0 (2021/11/30) 廃止 vari(String) → var(String,double)
    529//       *
    530//       * @param       key     ｷｰ
    531//       *
    532//       * @return      変数値
    533//       */
    534//      protected final double vard( final String key ) {
    535//              return str2dbl( var( key ) );                   // 6.7.9.1 (2017/05/19)
    536//      }
    537
    538        /**
    539         * ﾊﾟﾗﾒｰﾀｰのｷｰ一覧を配列形式で返します。
    540         * このﾊﾟﾗﾒｰﾀｰは、業務ﾛｼﾞｯｸ内でｾｯﾄされたﾊﾟﾗﾒｰﾀｰも含まれますのでご注意下さい。
    541         *
    542         * @return      ﾊﾟﾗﾒｰﾀｰのｷｰ配列
    543         */
    544        protected final String[] varKeys() {
    545                final Set<String> keys = variableMap.keySet();
    546                return keys.toArray( new String[keys.size()] );
    547        }
    548
    549        /**
    550         * 指定されたｷｰで値を登録します。
    551         * ﾊﾟﾗﾒｰﾀｰとしてこの業務ﾛｼﾞｯｸが呼ばれる際の引数となっている場合は、
    552         * ｴﾗｰとなります。
    553         *
    554         * @og.rev 5.2.1.0 (2010/10/01) ﾁｪｯｸのﾊﾞｸﾞを修正
    555         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    556         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
    557         *
    558         * @param       key     ｷｰ
    559         * @param       val     値
    560         */
    561        protected final void set( final String key, final String val ) {
    562                // 6.0.2.5 (2014/10/31) 素直に、variableMap で、ｷｰ有無を判定する。
    563//              if( variableMap.containsKey( key ) ) {
    564                if( mapGet( key ) != null ) {
    565                        final String errMsg = "すでに登録済みのｷｰを定義することはできません。"        + CR
    566                                                        + "   key =" + key                              + CR
    567                                                        + "   val =" + val                              + CR
    568//                                                      + "   元  =" + variableMap.get( key ) ;
    569                                                        + "   元  =" + mapGet( key ) ;
    570                        throw new OgRuntimeException( errMsg );
    571                }
    572
    573//              variableMap.put( key, val );
    574                if( key != null ) {
    575                        variableMap.put( key.toUpperCase(Locale.JAPAN), val );
    576                }
    577        }
    578
    579        /**
    580         * 指定されたｷｰで値(int型)を登録します。
    581         * ﾊﾟﾗﾒｰﾀｰとしてこの業務ﾛｼﾞｯｸが呼ばれる際の引数となっている場合は、
    582         * ｴﾗｰとなります。
    583         *
    584         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
    585         *
    586         * @param       key     ｷｰ
    587         * @param       val     値
    588         */
    589        protected final void set( final String key, final int val ) {
    590                set( key, String.valueOf( val ) );
    591        }
    592
    593        /**
    594         * 指定されたｷｰで値(double型)を登録します。
    595         * ﾊﾟﾗﾒｰﾀｰとしてこの業務ﾛｼﾞｯｸが呼ばれる際の引数となっている場合は、
    596         * ｴﾗｰとなります。
    597         *
    598         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
    599         *
    600         * @param       key     ｷｰ
    601         * @param       val     値
    602         */
    603        protected final void set( final String key, final double val ) {
    604                set( key, String.valueOf( val ) );
    605        }
    606
    607//      /**
    608//       * 処理中の行の指定されたｷｰ(ｶﾗﾑ名)の値を返します。
    609//       *
    610//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    611//       *
    612//       * @param       key     ｷｰ
    613//       *
    614//       * @return      値
    615//       */
    616//      protected final String line( final String key ) {
    617//              return line( key, row );
    618//      }
    619
    620//      /**
    621//       * ﾒｲﾝの配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙに対して、行を指定して値を取得します。
    622//       * 指定された行が範囲を超えている場合は、nullを返します。
    623//       *
    624//       * @og.rev 5.1.8.0 (2010/07/01) ﾃｰﾌﾞﾙに存在しないｶﾗﾑ名を指定した場合に、NullPointerExceptionが発生するﾊﾞｸﾞを修正
    625//       * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    626//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    627//       *
    628//       * @param       key     ｷｰ
    629//       * @param       rw      行番号(ｲﾝﾃﾞｯｸｽ)
    630//       *
    631//       * @return      値
    632//       */
    633//      protected final String line( final String key, final int rw ) {
    634//              if( table == null ) {
    635//                      // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    636//                      final String errMsg = "配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙがｾｯﾄされていないため、#line( String,int )ﾒｿｯﾄﾞはできません。"        + CR
    637//                                                      + "   line( " + key + "," + rw + " );"  + CR ;
    638//                      throw new OgRuntimeException( errMsg );
    639//              }
    640//              // 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
    641//
    642//              final int col = table.getColumnNo( key );
    643//
    644//              return col < 0 || rw < 0 || rw >= table.getRowCount() ? null : table.getValue( rw, col );
    645//      }
    646
    647//      /**
    648//       * 処理中の行の指定されたｶﾗﾑ番号の値を返します。
    649//       * line( String )は、毎回、ｶﾗﾑ番号を取得しているため、非効率です。
    650//       * ただし、一旦ｶﾗﾑ名から、ｶﾗﾑ番号を取得し、それを使用するのと、
    651//       * linei(String)や、lined(String) などの直接的なﾒｿｯﾄﾞもないため、
    652//       * 利用者側でそのあたりの処理を入れる必要があります。
    653//       *
    654//       * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。
    655//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    656//       *
    657//       * @param       col     ｶﾗﾑ番号
    658//       * @return      値
    659//       */
    660//      protected final String line( final int col ) {
    661//              return line( col, row );
    662//      }
    663
    664//      /**
    665//       * ﾒｲﾝの配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙに対して、行を指定して値を取得します。
    666//       * 指定された行が範囲を超えている場合は、nullを返します。
    667//       *
    668//       * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。
    669//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    670//       *
    671//       * @param       col     ｶﾗﾑ番号
    672//       * @param       rw      行番号(ｲﾝﾃﾞｯｸｽ)
    673//       * @return      値
    674//       */
    675//      protected final String line( final int col, final int rw ) {
    676//              if( table == null ) {
    677//                      // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    678//                      final String errMsg = "配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙがｾｯﾄされていないため、#line( String,int )ﾒｿｯﾄﾞはできません。"        + CR
    679//                                                      + "   line( " + col + "," + rw + " );"  + CR ;
    680//                      throw new OgRuntimeException( errMsg );
    681//              }
    682//
    683//              return col < 0 || rw < 0 || rw >= table.getRowCount() ? null : table.getValue( rw, col );
    684//      }
    685
    686//      /**
    687//       * 処理中の行の指定されたｷｰ(ｶﾗﾑ名)の値をint型に変換して返します。
    688//       *
    689//       * @og.rev 6.7.9.0 (2017/04/28) row を使用して、#linei( String,int )を呼びます。
    690//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    691//       *
    692//       * @param       key     ｷｰ
    693//       *
    694//       * @return      値
    695//       */
    696//      protected final int linei( final String key ) {
    697//              return str2int( line( key, row ) );                     // 6.7.9.1 (2017/05/19)
    698//      }
    699
    700//      /**
    701//       * ﾒｲﾝの配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙに対して、行を指定して値をint型に変換して返します。
    702//       * 指定された行が範囲を超えている場合は、nullを返します。
    703//       *
    704//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
    705//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    706//       *
    707//       * @param       key     ｷｰ
    708//       * @param       rw      行番号(ｲﾝﾃﾞｯｸｽ)
    709//       *
    710//       * @return      値
    711//       */
    712//      protected final int linei( final String key, final int rw ) {
    713//              return str2int( line( key, rw ) );                      // 6.7.9.1 (2017/05/19)
    714//      }
    715
    716//      /**
    717//       * 処理中の行の指定されたｷｰ(ｶﾗﾑ名)の値をdouble型に変換して返します。
    718//       *
    719//       * @og.rev 6.7.9.0 (2017/04/28) row を使用して、#lined( String,int )を呼びます。
    720//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    721//       *
    722//       * @param       key     ｷｰ
    723//       *
    724//       * @return      値
    725//       */
    726//      protected final double lined( final String key ) {
    727//              return str2dbl( line( key, row ) );                     // 6.7.9.1 (2017/05/19)
    728//      }
    729
    730//      /**
    731//       * ﾒｲﾝの配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙに対して、行を指定して値をdouble型に変換して返します。
    732//       * 指定された行が範囲を超えている場合は、nullを返します。
    733//       *
    734//       * @og.rev 6.7.9.0 (2017/04/28) nullと isEmpty() も、0 を返します。
    735//       * @og.rev 8.0.2.0 (2021/11/30) lineﾒｿｯﾄﾞ廃止(いまいち、使い道がない)
    736//       *
    737//       * @param       key     ｷｰ
    738//       * @param       rw      行番号(ｲﾝﾃﾞｯｸｽ)
    739//       *
    740//       * @return      値
    741//       */
    742//      protected final double lined( final String key, final int rw ) {
    743//              return str2dbl( line( key, rw ) );                      // 6.7.9.1 (2017/05/19)
    744//      }
    745
    746        /**
    747         * 指定のｶﾗﾑ名引数に相当するﾃﾞｰﾀを２重配列で返します。
    748         *
    749         * @og.rev 6.8.5.0 (2018/01/09) 新規追加
    750         *
    751         * @param       clmNms  値が参照されるｶﾗﾑ名配列(可変長引数)
    752         *
    753         * @return      指定された名引数に相当するﾃﾞｰﾀの２重配列
    754         * @og.rtnNotNull
    755         */
    756        protected String[][] getValues( final String... clmNms ) {
    757                // 6.9.8.0 (2018/05/28) FindBugs:ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで null 値を利用している
    758                if( table == null ) {
    759                        final String errMsg = "配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙがｾｯﾄされていないため、#getValues( String... )ﾒｿｯﾄﾞはできません。"    + CR
    760                                                        + "   clmNms= " + Arrays.toString( clmNms ) + " );"     + CR ;
    761                        throw new OgRuntimeException( errMsg );
    762                }
    763
    764                return ((ArrayTableModel)table).getValues( clmNms );
    765        }
    766
    767//      /**
    768//       * 文字列を整数に変換します。
    769//       * 文字列が、nullか、空文字列の場合は、0 を返します。
    770//       *
    771//       * @og.rev 6.7.9.1 (2017/05/19) 文字列を整数に変換します。
    772//       * @og.rev 8.0.2.0 (2021/11/30) str2intﾒｿｯﾄﾞ廃止(必要であれば、StringUtilを使用)
    773//       *
    774//       * @param       val     入力文字列
    775//       * @return      int値
    776//       */
    777//      protected final int str2int( final String val ) {
    778//              return val == null || val.isEmpty() ? 0 : Integer.parseInt( val );
    779//      }
    780
    781//      /**
    782//       * 文字列をdoubleに変換します。
    783//       * 文字列が、nullか、空文字列の場合は、0d を返します。
    784//       *
    785//       * @og.rev 6.7.9.1 (2017/05/19) 文字列をdoubleに変換します。
    786//       * @og.rev 8.0.2.0 (2021/11/30) str2dblﾒｿｯﾄﾞ廃止(必要であれば、StringUtilを使用)
    787//       *
    788//       * @param       val     入力文字列
    789//       * @return      double値
    790//       */
    791//      protected final double str2dbl( final String val ) {
    792//              return val == null || val.isEmpty() ? 0d : Double.parseDouble( val );
    793//      }
    794
    795        /**
    796         * 文字列配列をdouble配列に変換します。
    797         * 文字列が、nullか、空文字列の場合は、長さ０の配列を返します。
    798         *
    799         * @og.rev 6.8.5.0 (2018/01/09) 新規追加
    800         * @og.rev 8.0.2.0 (2021/11/30) StringUtil#nval(String.doubleを使用)
    801         *
    802         * @param       vals    double配列に変換する元の文字列配列
    803         * @return      指定された文字列配列に対するdoubleに変換された値配列
    804         * @og.rtnNotNull
    805         */
    806        protected final double[][] str2dblVals( final String[][] vals ) {
    807                if( vals == null || vals.length == 0 || vals[0] == null || vals[0].length == 0 ) {
    808                        return new double[0][0];
    809                }
    810
    811                final int rowLen = vals.length;
    812                final int colLen = vals[0].length;
    813
    814                final double[][] dbls = new double[rowLen][colLen];
    815
    816                for( int row=0; row<rowLen; row++ ) {
    817                        for( int col=0; col<colLen; col++ ) {
    818//                              dbls[row][col] = str2dbl( vals[row][col] );
    819                                dbls[row][col] = StringUtil.nval( vals[row][col],0d );  // 8.0.2.0 (2021/11/30)
    820                        }
    821                }
    822
    823                return dbls;
    824        }
    825
    826        /**
    827         * ﾃｰﾌﾞﾙのｶﾗﾑ名の一覧を配列形式で返します。
    828         *
    829         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    830         * @og.rev 8.0.2.0 (2021/11/30) ﾒｿｯﾄﾞ名変更(lineKeys → getNames)
    831         *
    832         * @return      ﾃｰﾌﾞﾙのｶﾗﾑ名配列
    833         */
    834//      protected final String[] lineKeys() {
    835        protected final String[] getNames() {
    836                if( table == null ) {
    837                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    838                        final String errMsg = "配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙがｾｯﾄされていないため、#lineKeys()ﾒｿｯﾄﾞはできません。" ;
    839                        throw new OgRuntimeException( errMsg );
    840                }
    841                else {
    842                        return table.getNames();
    843                }
    844        }
    845
    846//      /**
    847//       * ﾃｰﾌﾞﾙにｶﾗﾑが存在しているかを返します。
    848//       *
    849//       * @og.rev 5.2.0.0 (2010/09/01)
    850//       * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    851//       * @og.rev 8.0.2.0 (2021/11/30) isLineﾒｿｯﾄﾞ廃止(必要なら、DataModel#getColumnNo(String) で判定する)
    852//       *
    853//       * @param       clm     ｶﾗﾑ名
    854//       *
    855//       * @return      存在している場合true、存在していない場合false
    856//       */
    857//      protected final boolean isLine( final String clm ) {
    858//              if( table == null ) {
    859//                      // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    860//                      final String errMsg = "配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙがｾｯﾄされていないため、#isLine( String )ﾒｿｯﾄﾞはできません。"  + CR
    861//                                                      + "   isLine( " + clm + " );"   + CR ;
    862//                      throw new OgRuntimeException( errMsg );
    863//              }
    864//              return table.getColumnNo( clm ) >= 0 ;
    865//      }
    866
    867        /**
    868         * 業務ﾛｼﾞｯｸの戻り値をｾｯﾄします。
    869         *
    870         * @param       rtn     戻り値
    871         */
    872        protected final void rtn( final String rtn ) {
    873                bizRtn = rtn;
    874        }
    875
    876//      /**
    877//       * 子ﾛｼﾞｯｸを実行します。
    878//       * 実行する子ﾛｼﾞｯｸの呼び出しは、親ｸﾗｽと同じｿｰｽﾊﾟｽ、ｸﾗｽﾊﾟｽで呼び出しされます。
    879//       * 子ﾛｼﾞｯｸに渡す引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    880//       * また、子ﾛｼﾞｯｸの戻り値は、val("SUB_RETURN")で取得することができます。
    881//       *
    882//       * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すﾒｿｯﾄﾞは廃止。
    883//       *
    884//       * @param       subLogicName    子ﾛｼﾞｯｸ名
    885//       * @param       key                             ｷｰ(CSV形式)
    886//       * @param       val                             値(CSV形式)
    887//       *
    888//       * @return      処理が正常終了したか
    889//       */
    890//      protected final boolean call( final String subLogicName, final String key, final String val ) {
    891//              return call( subLogicName, key, val, row, table );
    892//      }
    893
    894        /**
    895         * 子ﾛｼﾞｯｸを実行します。
    896         * 実行する子ﾛｼﾞｯｸの呼び出しは、親ｸﾗｽと同じｿｰｽﾊﾟｽ、ｸﾗｽﾊﾟｽで呼び出しされます。
    897         * 子ﾛｼﾞｯｸに渡す引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    898         * この場合の値は、引数で指定された、配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙの行に対応する値になります。
    899         * また、子ﾛｼﾞｯｸの戻り値は、val("RETURN")で取得することができます。
    900         *
    901         * @og.rev 5.1.9.0 (2010/08/01) ｼｰｹﾝｽ対応
    902         * @og.rev 5.4.1.0 (2011/11/01) 値にｶﾝﾏが含まれている場合に正しく動作しないﾊﾞｸﾞを修正
    903         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    904         * @og.rev 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    905         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    906         * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すﾒｿｯﾄﾞは廃止。
    907         *
    908         * @param       subLogicName    子ﾛｼﾞｯｸ名
    909         * @param       key                             ｷｰ(CSV形式)
    910         * @param       val                             値(CSV形式)
    911//       * @param       rw                              行番号(ｲﾝﾃﾞｯｸｽ)
    912//       * @param       tbl                             配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    913         *
    914         * @return      処理が正常終了したか
    915         */
    916//      protected final boolean call( final String subLogicName, final String key, final String val, final int rw, final DataModel<String> tbl ) {
    917        protected final boolean call( final String subLogicName, final String key, final String val ) {
    918                // 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    919                if( loader == null ) {
    920                        final String errMsg = "#setLoader(HybsLoader)を先に実行しておいてください。"   + CR
    921                                                        + "   subLogicName =" + subLogicName    + CR
    922                                                        + "   key =" + key      + CR
    923                                                        + "   val =" + val      + CR
    924                                                        + "   ArrayTableModel=" + table ;
    925                        throw new OgRuntimeException( errMsg );
    926                }
    927
    928                final AbstractBizLogic subLogic = (AbstractBizLogic)loader.newInstance( subLogicName );
    929
    930                if( subLogic.isRequireTable() ) {
    931                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    932                        final String errMsg = "このｸﾗｽは、外部からﾃｰﾌﾞﾙﾓﾃﾞﾙをｾｯﾄする必要があるため、子ﾛｼﾞｯｸとして呼び出すことはできません。" + CR
    933                                                        + "  [ｸﾗｽ名=" + subLogic.getClass().getName() + "]"      + CR
    934                                                        + "   subLogicName =" + subLogicName
    935                                                        + "   key =[" + key + "]"
    936                                                        + "   val =[" + val + "]" + CR ;
    937                        throw new OgRuntimeException( errMsg );
    938                }
    939
    940                subLogic.setTransaction( tran );
    941                subLogic.setLoader( loader );
    942                subLogic.setKeys( StringUtil.csv2Array( key ) );
    943                // 5.4.1.0 (2011/11/01) 値にｶﾝﾏが含まれている場合に正しく動作しないﾊﾞｸﾞを修正
    944                // 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
    945                final String[] vals = StringUtil.csv2Array( val );
    946                replaceParam( vals );                   // 8.0.2.0 (2021/11/30) 配列内部を書き換えます。
    947//              for( int i=0; i<vals.length; i++ ) {
    948//                      vals[i] = replaceParam( vals[i], row, table );
    949//              }
    950                subLogic.setVals( vals );
    951                subLogic.setUserId( variableMap.get( "CON.USERID" ) );
    952                subLogic.setParentPgId( variableMap.get( "CON.PGID" ) );
    953                if( debugFlag ) {
    954                        subLogic.setDebug();
    955                }
    956
    957                final boolean rtn;                                              // 6.3.9.0 (2015/11/06) Found 'DU'-anomaly for variable(PMD)
    958                try {
    959                        rtn = subLogic.exec();
    960                }
    961                catch( final Throwable th ) {
    962                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    963                        final String errMsg = "子ﾛｼﾞｯｸの呼び出しでｴﾗｰが発生しました。" + CR
    964                                                        + "   subLogicName =" + subLogicName  + CR
    965                                                        + "   key =[" + key + "]"
    966                                                        + "   val =[" + val + "]" + CR ;
    967                        throw new OgRuntimeException( errMsg ,th );
    968                }
    969                variableMap.put( "RETURN", subLogic.getReturn() );
    970
    971                if( debugFlag ) { debug( subLogic.getDebugMsg() ); }
    972
    973                final ErrMsg[] errs = subLogic.getErrMsg().toArray();
    974                if( errs.length > 0 ) {
    975                        final ErrorMessage errMsgTmp = new ErrorMessage();
    976                        for( int i=0; i<errs.length; i++ ) {
    977                                errMsgTmp.addMessage( errs[i].copy( row ) );
    978                        }
    979//                      errMsg.append( errMsgTmp );
    980                        errMessage.append( errMsgTmp );                                                                         // 8.3.1.0 (2022/10/14)
    981                }
    982
    983                return rtn;
    984        }
    985
    986//      /**
    987//       * SQLを実行します。
    988//       * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    989//       * select文を発行した場合、その結果ｾｯﾄは、var(ｶﾗﾑ名)で取得することができます。
    990//       * 2行以上が返された場合でも、1行目のみが登録されます。
    991//       * また、検索件数、更新件数については、var("SQL_ROWCOUNT")で取得することができます。
    992//       *
    993//       * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すﾒｿｯﾄﾞは廃止。
    994//       *
    995//       * @param       sq      SQL文字列
    996//       */
    997//      protected final void sql( final String sq ) {
    998//              sql( sq, row, table );
    999//      }
    1000
    1001        /**
    1002         * SQLを実行します。
    1003         * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    1004         * [XXXX]形式の変数の置き換えには、引数で指定された配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙの行が使用されます。
    1005         * select文を発行した場合、その結果ｾｯﾄは、var(ｶﾗﾑ名)で取得することができます。
    1006         * 2行以上が返された場合でも、1行目のみが登録されます。
    1007         * また、検索件数、更新件数については、var("SQL_ROWCOUNT")で取得することができます。
    1008         *
    1009         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    1010         * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すﾒｿｯﾄﾞは廃止。
    1011         *
    1012         * @param       sq      SQL文字列
    1013//       * @param       rw      行番号(ｲﾝﾃﾞｯｸｽ)
    1014//       * @param       tbl     配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    1015         */
    1016//      protected final void sql( final String sq, final int rw, final DataModel<String> tbl ) {
    1017        protected final void sql( final String sq ) {
    1018                final DataModel<String> tbl2 = execSQL( sq, row, table );
    1019
    1020                if( tbl2 != null && tbl2.getRowCount() > 0 ) {
    1021                        final String[] names = tbl2.getNames();
    1022                        final String[] vals = tbl2.getValues( 0 );
    1023                        for( int i=0; i<names.length; i++ ) {
    1024                                variableMap.put( names[i], vals[i] );                                                   // execSQLでnamesを大文字化済
    1025                        }
    1026                }
    1027        }
    1028
    1029        /**
    1030         * ｼｰｹﾝｽ名よりｼｰｹﾝｽｵﾌﾞｼﾞｪｸﾄを検索し、次の値を取り出します。
    1031         * DBに対するｼｰｹﾝｽｵﾌﾞｼﾞｪｸﾄは予め作成されている必要があります。
    1032         *
    1033         * また、MySQLの場合は、ｼｰｹﾝｽｵﾌﾞｼﾞｪｸﾄが実装されていないため、
    1034         * 内部的には、引数のｼｰｹﾝｽ名と同じ名前のﾃｰﾌﾞﾙから、Integer型の
    1035         * "SEQID"という項目名を検索することにより、ｼｰｹﾝｽをｴﾐｭﾚｰﾄしています。
    1036         *
    1037         * @og.rev 5.1.9.0 (2010/08/01) 新規追加
    1038         * @og.rev 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    1039         *
    1040         * @param       seqName ｼｰｹﾝｽ名
    1041         *
    1042         * @return      ｼｰｹﾝｽ番号
    1043         * @see org.opengion.fukurou.db.DBFunctionName#getSequence(String,Transaction)
    1044         */
    1045        protected final int seq( final String seqName ) {
    1046                // 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    1047                if( dbName == null ) {
    1048                        final String errMsg = "#exec()を先に実行しておいてください。"  + CR
    1049                                                        + "   seqName =" + seqName ;
    1050                        throw new OgRuntimeException( errMsg );
    1051                }
    1052
    1053                return dbName.getSequence( seqName, tran );
    1054        }
    1055
    1056        /**
    1057         * SQLを実行します。
    1058         *
    1059         * @param       sq      SQL文字列
    1060         * @param       rw      行番号(ｲﾝﾃﾞｯｸｽ)
    1061         * @param       tbl     配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    1062         *
    1063         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1064         *
    1065         * @return      結果ｾｯﾄ(配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ)
    1066         *
    1067         * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    1068         * @og.rev 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&ﾊﾞｸﾞ修正)
    1069         * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData を ConnectionFactory経由で取得。(PostgreSQL対応)、setNull 対応
    1070         * @og.rev 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    1071         * @og.rev 6.4.2.1 (2016/02/05) try-with-resources 文で記述。
    1072         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    1073         * @og.rev 6.9.3.0 (2018/03/26) ﾐｽ修正(検索件数のところを、ﾌｪｯﾁ件数を取得していた)
    1074         * @og.rev 6.9.3.0 (2018/03/26) ﾃﾞｰﾀ検索時のﾌｪｯﾁｻｲｽﾞを設定。
    1075         */
    1076        private DataModel<String> execSQL( final String sq, final int rw, final DataModel<String> tbl ) {
    1077                // 6.3.9.0 (2015/11/06) ｺﾝｽﾄﾗｸﾀで初期化されていないﾌｨｰﾙﾄﾞを null ﾁｪｯｸなしで利用している(findbugs)
    1078                if( conn == null ) {
    1079                        final String errMsg = "#setTransaction(Transaction)を先に実行しておいてください。"     + CR
    1080                                                        + "   sql =" + sq               + CR
    1081                                                        + "   ArrayTableModel=" + tbl ;
    1082                        throw new OgRuntimeException( errMsg );
    1083                }
    1084
    1085                String sql = replaceParam( sq, false ); // [XXXX]の変換はここでは行わない。
    1086                Formatter format = null ;
    1087                if( tbl != null && sql.indexOf( '[' ) >= 0 ) {
    1088                        format = getFormatter( sql, tbl );
    1089                        sql = format.getQueryFormatString();
    1090                }
    1091
    1092                DataModel<String>       tbl2    = null;
    1093                // 6.4.2.1 (2016/02/05) try-with-resources 文
    1094                try( PreparedStatement pstmt = conn.prepareStatement( sql ) ) {
    1095                        if( tbl != null && format != null ) {
    1096                                final int[] clmNo = format.getClmNos();
    1097
    1098                                // 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す。(PostgreSQL対応)
    1099                                if( useParamMetaData ) {
    1100                                        final ParameterMetaData pMeta = pstmt.getParameterMetaData();
    1101                                        for( int i=0; i<clmNo.length; i++ ) {
    1102                                                final int type = pMeta.getParameterType( i+1 );
    1103                                                // 5.3.8.0 (2011/08/01) setNull 対応
    1104                                                final String val = tbl.getValue( rw, clmNo[i] );
    1105                                                if( val == null || val.isEmpty() ) {
    1106                                                        pstmt.setNull( i+1, type );
    1107                                                }
    1108                                                else {
    1109                                                        pstmt.setObject( i+1, val, type );
    1110                                                }
    1111                                        }
    1112                                }
    1113                                else {
    1114                                        for( int i=0; i<clmNo.length; i++ ) {
    1115                                                pstmt.setObject( i+1, tbl.getValue( rw, clmNo[i] ) );
    1116                                        }
    1117                                }
    1118                        }
    1119                        final boolean status = pstmt.execute();
    1120                        // 6.4.2.1 (2016/02/05) try-with-resources 文
    1121                        try( ResultSet result = pstmt.getResultSet() ) {
    1122                                if( status ) {
    1123                                        result.setFetchSize( DB_FETCH_SIZE );                           // 6.9.3.0 (2018/03/26) ﾃﾞｰﾀ検索時のﾌｪｯﾁｻｲｽﾞ
    1124
    1125                                        final ResultSetMetaData metaData = result.getMetaData();
    1126                                        final int cols = metaData.getColumnCount();
    1127
    1128                                        String[] names = new String[cols];
    1129                                        for( int i=0; i<cols; i++ ) {
    1130                                                // 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&ﾊﾞｸﾞ修正)
    1131                                                names[i] = metaData.getColumnLabel( i+1 ).toUpperCase( Locale.JAPAN );
    1132                                        }
    1133
    1134                                        final String[][] tblVals = DBUtil.resultToArray( result, false );
    1135                                        tbl2 = new ArrayTableModel( names, tblVals );
    1136
    1137//                                      variableMap.put( "SQL_ROWCOUNT", String.valueOf( pstmt.getFetchSize() ) );
    1138                                        variableMap.put( "SQL_ROWCOUNT", String.valueOf( tbl2.getRowCount() ) );                        // 6.9.3.0 (2018/03/26) ﾐｽ修正
    1139                                }
    1140                                else {
    1141                                        variableMap.put( "SQL_ROWCOUNT", String.valueOf( pstmt.getUpdateCount() ) );
    1142                                }
    1143                        }
    1144                }
    1145                catch( final SQLException ex ) {                // catch は、close() されてから呼ばれます。
    1146                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1147                        final String errMsg = "配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙの生成に失敗しました。" + CR
    1148                                                        + "   sql =" + sql              + CR
    1149                                                        + "   ArrayTableModel=" + tbl ;
    1150                        throw new OgRuntimeException( errMsg,ex );
    1151                }
    1152                return tbl2;
    1153        }
    1154
    1155        /**
    1156         * 検索用SQLを実行して、Consumer#accept に検索結果の配列を繰り返しセットします。
    1157         *
    1158         * 内部でResultSetValue のカーソルを回すため、大量のデータについて
    1159         * 順次処理する場合に使用します。
    1160         *
    1161         * @og.rev 8.2.0.3 (2022/06/30) 内部でカーソルを回す検索用SQLを実行する
    1162         * @og.rev 8.2.1.0 (2022/07/15) querySQL では、[XXXX]の変換 自体を行わない
    1163         *
    1164         * @param       sq              SQL文字列
    1165         * @param       call    CallBack関数(Consumer)
    1166         */
    1167        protected void querySQL( final String sq , final Consumer<String[]> call ) {
    1168                if( conn == null ) {
    1169                        final String errMsg = "#setTransaction(Transaction)を先に実行しておいてください。"     + CR
    1170                                                        + "   sql =" + sq               + CR ;
    1171                        throw new OgRuntimeException( errMsg );
    1172                }
    1173
    1174                final String sql = replaceParam( sq, false ); // [XXXX]の変換はここでは行わない。
    1175//              8.2.1.0 (2022/07/15) querySQL では、[XXXX]の変換 自体を行わない
    1176//              Formatter format = null ;
    1177//              if( table != null && sql.indexOf( '[' ) >= 0 ) {
    1178//                      format = getFormatter( sql, table );
    1179//                      sql = format.getQueryFormatString();
    1180//              }
    1181
    1182                try( PreparedStatement pstmt = conn.prepareStatement( sql ) ) {
    1183                        try( ResultSet result = pstmt.executeQuery() ) {
    1184        //                      result.setFetchSize( DB_FETCH_SIZE );
    1185                                try( ResultSetValue rsv = new ResultSetValue( result ) ) {
    1186                                        while( rsv.next() ) {
    1187                                                call.accept( rsv.getValues() );
    1188                                        }
    1189                                }
    1190                        }
    1191                }
    1192                catch( final SQLException ex ) {                // catch は、close() されてから呼ばれます。
    1193                        final String errMsg = "検索系SQL の実行に生成に失敗しました。"   + CR
    1194                                                        + "   sql =" + sql              + CR ;
    1195                        throw new OgRuntimeException( errMsg,ex );
    1196                }
    1197        }
    1198
    1199        /**
    1200         * ｴﾗｰﾒｯｾｰｼﾞを追加します。
    1201         * ｴﾗｰﾒｯｾｰｼﾞの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    1202         *
    1203         * @param       kekka   ｴﾗｰﾚﾍﾞﾙ
    1204         * @param       id              ｴﾗｰﾒｯｾｰｼﾞID
    1205         * @param       args    ｴﾗｰﾒｯｾｰｼﾞﾊﾟﾗﾒｰﾀｰ
    1206         */
    1207        protected final void error( final int kekka, final String id, final String... args ) {
    1208                error( row, kekka, id, args );
    1209        }
    1210
    1211        /**
    1212         * 行指定でｴﾗｰﾒｯｾｰｼﾞを追加します。
    1213         * ｴﾗｰﾒｯｾｰｼﾞの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    1214         *
    1215         * @param       rw              行番号(ｲﾝﾃﾞｯｸｽ)
    1216         * @param       kekka   ｴﾗｰﾚﾍﾞﾙ
    1217         * @param       id              ｴﾗｰﾒｯｾｰｼﾞID
    1218         * @param       args    ｴﾗｰﾒｯｾｰｼﾞﾊﾟﾗﾒｰﾀｰ
    1219         */
    1220        protected final void error( final int rw, final int kekka, final String id, final String... args ) {
    1221//              errMsg.addMessage( rw, kekka, id, replaceParam( args ) );
    1222                errMessage.addMessage( rw, kekka, id, replaceParam( args ) );                   // 8.3.1.0 (2022/10/14)
    1223        }
    1224
    1225        /**
    1226         * ﾊﾟﾗﾒｰﾀｰの必須ﾁｪｯｸを行います。
    1227         * ｷｰは、CSV形式で複数指定することができます。
    1228         *
    1229         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
    1230         *
    1231         * @param       cs      ｶﾗﾑ(CSV形式)
    1232         *
    1233         * @return      ｴﾗｰが発生した場合はfalse、それ以外はtrue
    1234         */
    1235        protected final boolean must( final String cs ) {
    1236                if( cs == null || cs.isEmpty() ) {
    1237                        return true;
    1238                }
    1239
    1240                final String[] clms = StringUtil.csv2Array( cs );
    1241                for( int i=0; i<clms.length; i++ ) {
    1242//                      final String val = variableMap.get( clms[i] );                                          // 8.3.0.1 (2022/08/12)
    1243                        final String val = mapGet( clms[i] );
    1244                        if( val == null || val.isEmpty() ) {
    1245//                              error( 2, "ERR0012", "{#" + clms[i] + "}" );
    1246                                error( NG, "ERR0012", "{#" + clms[i] + "}" );                                   // 7.2.9.5 (2020/11/28)
    1247                                return false ;
    1248                        }
    1249                }
    1250                return true;
    1251        }
    1252
    1253        /**
    1254         * ﾏｽﾀﾁｪｯｸを行います。
    1255         *
    1256         * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加
    1257         *
    1258         * @see #exist(String, String, String, String, String, String)
    1259         * @param       type    ｴﾗｰﾁｪｯｸのﾀｲﾌﾟ
    1260         * @param       tblId   ﾃｰﾌﾞﾙ名
    1261         * @param       ns              ｶﾗﾑ(CSV形式)
    1262         * @param       vs              値(CSV形式)
    1263         *
    1264         * @return      ｴﾗｰが発生した場合はfalse、それ以外はtrue
    1265         */
    1266        protected final boolean exist( final String type, final String tblId, final String ns, final String vs ) {
    1267                return exist( type, tblId, ns, vs, null, null,true );
    1268        }
    1269
    1270        /**
    1271         * ﾏｽﾀﾁｪｯｸを行います。
    1272         *
    1273         * 引数に指定されたﾃｰﾌﾞﾙ名、及び条件句を生成するためのｶﾗﾑ、値から
    1274         * 件数を取得し、typeに応じて件数ﾁｪｯｸを行います。
    1275         * (ｶﾗﾑ、値には、CSV形式で複数指定することができます)
    1276         *  type=true  存在する場合true  存在しない場合false
    1277         *  type=false 存在する場合false 存在しない場合true
    1278         *  type=one   1件以内    true  2件以上     false
    1279         *
    1280         * 必須ﾁｪｯｸの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    1281         *
    1282         * また、固定値ｶﾗﾑ、値にも条件となるｶﾗﾑ及び値を指定することができますが、
    1283         * ここで指定されたｶﾗﾑは、ｴﾗｰﾒｯｾｰｼﾞ表示時にｶﾗﾑ、値が画面に表示されません。
    1284         *
    1285         * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加
    1286         *
    1287         * @param       type    ｴﾗｰﾁｪｯｸのﾀｲﾌﾟ
    1288         * @param       tblId   ﾃｰﾌﾞﾙ名
    1289         * @param       ns              ｶﾗﾑ(CSV形式)
    1290         * @param       vs              値(CSV形式)
    1291         * @param       conNs   固定値ｶﾗﾑ(CSV形式)
    1292         * @param       conVs   固定値(CSV形式)
    1293         *
    1294         * @return      ｴﾗｰが発生した場合はfalse、それ以外はtrue
    1295         */
    1296        protected final boolean exist( final String type, final String tblId
    1297                        , final String ns, final String vs, final String conNs, final String conVs ) {
    1298                return exist( type, tblId, ns, vs, conNs, conVs,true );
    1299        }
    1300
    1301        /**
    1302         * ﾏｽﾀﾁｪｯｸを行います。
    1303         * 引数に指定されたﾃｰﾌﾞﾙ名、及び条件句を生成するためのｶﾗﾑ、値から
    1304         * 件数を取得し、typeに応じて件数ﾁｪｯｸを行います。
    1305         * (ｶﾗﾑ、値には、CSV形式で複数指定することができます)
    1306         *  type=true  存在する場合true  存在しない場合false
    1307         *  type=false 存在する場合false 存在しない場合true
    1308         *  type=one   1件以内    true  2件以上     false
    1309         *
    1310         * 必須ﾁｪｯｸの引数には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    1311         *
    1312         * また、固定値ｶﾗﾑ、値にも条件となるｶﾗﾑ及び値を指定することができますが、
    1313         * ここで指定されたｶﾗﾑは、ｴﾗｰﾒｯｾｰｼﾞ表示時にｶﾗﾑ、値が画面に表示されません。
    1314         *
    1315         * isErrThrow は、ｴﾗｰが発生した場合に、ｴﾗｰﾒｯｾｰｼﾞ（ErrorMessage）に書き込むかどうかを指定します。
    1316         * 基本は、互換性を考慮し、true(書き込む)です。
    1317         * false にするｹｰｽは、存在ﾁｪｯｸを行い、あれば更新、なければ追加 など後続処理を行いたい場合に使います。
    1318         *
    1319         * @og.rev 5.6.3.1 (2013/04/05) isErrThrow 引数を追加
    1320         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1321         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    1322         *
    1323         * @param       type            ｴﾗｰﾁｪｯｸのﾀｲﾌﾟ
    1324         * @param       tblId           ﾃｰﾌﾞﾙ名
    1325         * @param       ns                      ｶﾗﾑ(CSV形式)
    1326         * @param       vs                      値(CSV形式)
    1327         * @param       conNs           固定値ｶﾗﾑ(CSV形式)
    1328         * @param       conVs           固定値(CSV形式)
    1329         * @param       isErrThrow      判定結果がfalseの場合に、error関数を呼ぶ場合は、true。呼ばない場合は、falseをｾｯﾄします。
    1330         *
    1331         * @return      ｴﾗｰが発生した場合はfalse、それ以外はtrue
    1332         */
    1333        protected final boolean exist( final String type, final String tblId
    1334                        , final String ns, final String vs, final String conNs, final String conVs, final boolean isErrThrow ) {
    1335                if( ns == null || ns.isEmpty() || vs == null || vs.isEmpty() ) {
    1336                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1337                        final String errMsg = "ｶﾗﾑ又は、値にnullは指定できません。"   + CR
    1338                                                        + "   ns =[" + ns + "]"
    1339                                                        + "   vs =[" + vs + "]" ;
    1340                        throw new OgRuntimeException( errMsg );
    1341                }
    1342
    1343                final String namesStr   = ns + ( conNs == null || conNs.isEmpty() ? "" : "," + conNs );
    1344                final String[] namesArr = StringUtil.csv2Array( namesStr );
    1345                final String valsStr    = vs + ( conVs == null || conVs.isEmpty() ? "" : "," + conVs );
    1346                final String[] valsArr  = StringUtil.csv2Array( valsStr );
    1347                if( namesArr.length != valsArr.length ) {
    1348                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1349                        final String errMsg = "ｶﾗﾑと値の個数が異なります。"                 + CR
    1350                                                        + "   names = [" + namesStr     + "]"   + CR
    1351                                                        + "   vals  = [" + valsStr      + "]";
    1352                        throw new OgRuntimeException( errMsg );
    1353                }
    1354
    1355                final StringBuilder sb = new StringBuilder( BUFFER_MIDDLE );
    1356                sb.append( "select count(*) CNT from " ).append( tblId );
    1357                for( int i=0 ;i<namesArr.length; i++ ) {
    1358                        if( i==0 )      { sb.append( " where " ); }
    1359                        else            { sb.append( " and " ); }
    1360                        sb.append( namesArr[i] ).append( " = " ).append( valsArr[i] );
    1361                }
    1362
    1363                int count = 0;
    1364                final DataModel<String> tbl2 = execSQL( sb.toString(), row, table );            // 6.7.9.1 (2017/05/19)
    1365                if( tbl2 != null && tbl2.getRowCount() >= 0 ) {
    1366                        count = Integer.parseInt( tbl2.getValues( 0 )[0] );                     // 6.0.2.4 (2014/10/17) ﾒｿｯﾄﾞ間違い
    1367                }
    1368
    1369                final String repVals = replaceParam( vs );
    1370                if( "true".equalsIgnoreCase( type ) ) {
    1371                        // ERR0025=ﾃﾞｰﾀ未登録ｴﾗｰ。ｷｰ={0}、値={1} のﾃﾞｰﾀは、存在していません。
    1372                        if( count <= 0 ) {
    1373                                if( isErrThrow ) { error( NG, "ERR0025", "{#" + ns + "}", repVals ); }  // 5.6.3.1 (2013/04/05)
    1374                                return false;
    1375                        }
    1376                }
    1377                else if( "false".equalsIgnoreCase( type ) ) {
    1378                        // ERR0026=ﾃﾞｰﾀ登録済みｴﾗｰ。ｷｰ={0}、値={1} のﾃﾞｰﾀは、すでに存在しています。
    1379                        if( count > 0 ) {
    1380                                if( isErrThrow ) { error( NG, "ERR0026", "{#" + ns + "}", repVals ); }  // 5.6.3.1 (2013/04/05)
    1381                                return false;
    1382                        }
    1383                }
    1384                else if( "one".equalsIgnoreCase( type ) ) {
    1385                        // ERR0027=ﾃﾞｰﾀ２重登録ｴﾗｰ。ｷｰ={0}、値={1} のﾃﾞｰﾀは、重複して存在しています。
    1386                        if( count > 1 ) {
    1387                                if( isErrThrow ) { error( NG, "ERR0027", "{#" + ns + "}", repVals ); }  // 5.6.3.1 (2013/04/05)
    1388                                return false;
    1389                        }
    1390                }
    1391                else {
    1392                        // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1393                        final String errMsg = "typeは、true、false、oneのいずれかで指定する必要があります。"  + CR
    1394                                                        + "   type = [" + type  + "]";
    1395                        throw new OgRuntimeException( errMsg );
    1396                }
    1397                return true;
    1398        }
    1399
    1400        /**
    1401         * 引数に指定されたｷｰ、値をﾏｯﾌﾟ形式に変換します。
    1402         *
    1403         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
    1404         * @og.rev 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1405         * @og.rev 8.3.0.1 (2022/08/12) keyを大文字変換
    1406         */
    1407        private void makeParamMap() {
    1408                if( keys != null && vals != null ) {
    1409                        if( keys.length == vals.length ) {
    1410                                for( int i=0; i<keys.length; i++ ) {
    1411//                                      variableMap.put( keys[i], vals[i] );
    1412                                        if( keys[i] != null ) {
    1413                                                variableMap.put( keys[i].toUpperCase(Locale.JAPAN), vals[i] );  // 8.3.0.1 (2022/08/12)
    1414                                        }
    1415                                }
    1416                        }
    1417                        else {
    1418                                // 5.6.7.0 (2013/07/27) Exception を throw するとき、一旦、errMsg 変数にｾｯﾄします。
    1419                                final String errMsg = "keysとvalsの個数が異なります。"             + CR
    1420                                                        + "   keys   =" + Arrays.toString( keys )               + CR
    1421                                                        + "   vals   =" + Arrays.toString( vals ) ;
    1422                                throw new OgRuntimeException( errMsg );
    1423                        }
    1424                }
    1425
    1426                final String ymdh = DateSet.getDate( "yyyyMMddHHmmss" );                // 5.5.7.2 (2012/10/09) HybsDateUtil を利用
    1427                variableMap.put( "CON.YMDH", ymdh );
    1428                variableMap.put( "CON.YMD", ymdh.substring( 0,8 ) );
    1429                variableMap.put( "CON.HMS", ymdh.substring( 8 ) );
    1430
    1431                variableMap.put( "CON.PGID", this.getClass().getSimpleName() );
    1432        }
    1433
    1434        /**
    1435         * {&#064;XXXX}形式及び[XXXX]形式の文字列配列の置き換えを行います。
    1436         *
    1437         * @og.rev 6.2.2.0 (2015/03/27) #replaceParam( String[] , int , ArrayTableModel ) 廃止に伴う処置
    1438         * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
    1439         *
    1440         * @param       str     置き換え対象の配列
    1441         *
    1442         * @return      置き換え結果の文字列(引数配列の内部を書き換えます)
    1443         */
    1444        private String[] replaceParam( final String[] str ) {
    1445                for( int i=0; i<str.length; i++ ) {
    1446//                      str[i] = replaceParam( str[i], row, table );
    1447                        str[i] = replaceParam( str[i], true );                  // [XXXX]の変換を行う。
    1448                }
    1449                return str;
    1450        }
    1451
    1452        /**
    1453         * {&#064;XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。
    1454         *
    1455         * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
    1456         *
    1457         * @param       str     置き換え対象の文字列
    1458         *
    1459         * @return      置き換え結果の文字列
    1460         */
    1461        private String replaceParam( final String str ) {
    1462//              return replaceParam( str, row, table );
    1463                return replaceParam( str, true );                                       // [XXXX]の変換を行う。
    1464        }
    1465
    1466//      /**
    1467//       * {&#064;XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。
    1468//       * isRepTableにfalseを指定した場合、Formatterによる[XXXX]変換は行われません。
    1469//       * (SQLの変換の場合は、PreparedStatementで処理させるため、[XXXX]の変換は行わない。)
    1470//       *
    1471//       * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
    1472//       *
    1473//       * @param       str                     置き換え対象の文字列
    1474//       * @param       isRepTable      Formatterによる[XXXX]変換を行うか
    1475//       *
    1476//       * @return      置き換え結果の文字列
    1477//       */
    1478//      private String replaceParam( final String str, final boolean isRepTable ) {
    1479//              return isRepTable ? replaceParam( str, row, table) : replaceParam( str, 0, null ) ;
    1480//      }
    1481
    1482        /**
    1483         * {&#064;XXXX}形式及び[XXXX]形式の文字列の置き換えを行います。
    1484         * [XXXX]形式の置き換えには、引数で指定された配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ、行番号(ｲﾝﾃﾞｯｸｽ)を使用します。
    1485         *
    1486         * @og.rev 5.1.8.0 (2010/07/01) 引数ﾁｪｯｸ漏れ対応
    1487         * @og.rev 5.3.9.0 (2011/09/01) nullが連続する場合にｾﾞﾛｽﾄﾘﾝｸﾞに置き換えられないﾊﾞｸﾞを修正
    1488         * @og.rev 6.4.3.2 (2016/02/19) Formatterを、値が null の場合は、ｾﾞﾛ文字列を設定する。
    1489         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    1490         * @og.rev 8.0.2.0 (2021/11/30) #replaceParam( String , int , DataModel ) 廃止に伴う処置
    1491         *
    1492         * @param       str                     置き換え対象の文字列
    1493         * @param       isRepTable      Formatterによる[XXXX]変換を行うか
    1494//       * @param       rw                      行番号(ｲﾝﾃﾞｯｸｽ)
    1495//       * @param       tbl                     配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    1496         *
    1497         * @return      置き換え結果の文字列
    1498         */
    1499//      private String replaceParam( final String str, final int rw, final DataModel<String> tbl ) {
    1500        private String replaceParam( final String str, final boolean isRepTable ) {
    1501                // 5.1.8.0 (2010/07/01) 引数ﾁｪｯｸ漏れ対応
    1502                if( str == null || str.isEmpty() ) { return ""; }
    1503
    1504                String rtn = str;
    1505
    1506                // {@XXXX}の変換
    1507                if( !variableMap.isEmpty() && rtn.indexOf( "{@" ) >= 0 ) {              // 6.1.1.0 (2015/01/17) refactoring
    1508                        final SystemParameter sysParam = getSysParam( rtn );
    1509                        rtn = sysParam.replace( variableMap );
    1510                }
    1511
    1512                // [XXXX]の変換
    1513//              if( tbl != null && rtn.indexOf( '[' ) >= 0 ) {
    1514                if( isRepTable && rtn.indexOf( '[' ) >= 0 ) {
    1515                        final Formatter format = getFormatter( rtn, table );
    1516                        rtn = format.getFormatString( row );
    1517                }
    1518
    1519                return rtn;
    1520        }
    1521
    1522        /**
    1523         * [XXXX]変換を行うためのFormatterを取得します。
    1524         *
    1525         * @og.rev 6.4.3.4 (2016/03/11) Formatterに新しいｺﾝｽﾄﾗｸﾀｰを追加する。
    1526         * @og.rev 6.4.3.4 (2016/03/11) Map#computeIfAbsent で対応する。
    1527         * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    1528         *
    1529         * @param       str     変換文字列
    1530         * @param       tbl     配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    1531         *
    1532         * @return      Formatterｵﾌﾞｼﾞｪｸﾄ
    1533         */
    1534        private Formatter getFormatter( final String str, final DataModel<String> tbl ) {
    1535                // Map#computeIfAbsent ： 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
    1536                final String key = str + tbl.toString();
    1537                return formatMap.computeIfAbsent( key , k -> new Formatter( tbl,str ) );
    1538        }
    1539
    1540        /**
    1541         * {&#064;XXXX}変換を行うためのSystemParameterｵﾌﾞｼﾞｪｸﾄを取得します。
    1542         *
    1543         * @og.rev 6.4.3.3 (2016/03/04) ConcurrentHashMap の not null制限のﾁｪｯｸ追加
    1544         *
    1545         * @param       str     変換文字列
    1546         *
    1547         * @return      SystemParameterｵﾌﾞｼﾞｪｸﾄ
    1548         */
    1549        private SystemParameter getSysParam( final String str ) {
    1550                // 6.4.3.3 (2016/03/04) ｷｰが null のときも、SystemParameter ｵﾌﾞｼﾞｪｸﾄを構築しているので、
    1551                // それも合わせて、Mapで管理するようにします。
    1552                final String key = str == null ? "NULL" : str ;
    1553                // Map#computeIfAbsent ： 戻り値は、既存の、または計算された値。追加有り、置換なし、削除なし
    1554                return sysParamMap.computeIfAbsent( key , k -> new SystemParameter( k ) );
    1555        }
    1556
    1557//      /**
    1558//       * 検索SQLを実行し、結果を配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙとして返します。
    1559//       * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    1560//       * また、検索件数については、var("SQL_ROWCOUNT")で取得することができます。
    1561//       *
    1562//       * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    1563//       * @og.rev 8.0.2.0 (2021/11/30) BizLogic_CURSOR で使用しているだけなので、廃止。
    1564//       *
    1565//       * @param       sq      SQL文
    1566//       *
    1567//       * @return      配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    1568//       */
    1569//      protected final DataModel<String> createTableBySql( final String sq ) {
    1570////            return createTableBySql( sq, row, table );
    1571//              return execSQL( sq, row, table );
    1572//      }
    1573
    1574//      /**
    1575//       * 検索SQLを実行し、結果を配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙとして返します。
    1576//       * SQL文には、{&#064;XXXX}形式及び[XXXX]形式の変数を使用することができます。
    1577//       * [XXXX]形式の変数の置き換えには、引数で指定された配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙの行が使用されます。
    1578//       * また、検索件数については、var("SQL_ROWCOUNT")で取得することができます。
    1579//       *
    1580//       * @og.rev 6.7.9.1 (2017/05/19) ArrayTableModel をDataModel に変更。
    1581//       * @og.rev 8.0.2.0 (2021/11/30) 外部から、行番号とDataModelを渡すﾒｿｯﾄﾞは廃止。
    1582//       *
    1583//       * @param       sq      SQL文
    1584//       * @param       rw      行番号(ｲﾝﾃﾞｯｸｽ)
    1585//       * @param       tbl     配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    1586//       *
    1587//       * @return      配列型ﾃｰﾌﾞﾙﾓﾃﾞﾙ
    1588//       */
    1589//      protected final DataModel<String> createTableBySql( final String sq, final int rw, final DataModel<String> tbl ) {
    1590//              return execSQL( sq, rw, tbl );
    1591//      }
    1592
    1593        /**
    1594         * 変数に関連付けた値を、返します。
    1595         * これは、BizLogicから、呼び出し元のJSPに、RETURN 変数以外の {&#064;XXXX} ﾊﾟﾗﾒｰﾀを返します。
    1596         * 既存のｱﾄﾘﾋﾞｭｰﾄがあれば、上書きされます。
    1597         *
    1598         * @og.rev 6.9.9.0 (2018/08/20) 戻り値を返せるようにします。
    1599         *
    1600         * @param       key     ｷｰ
    1601         * @param       val     値
    1602         *
    1603         */
    1604        protected final void setRtnMap( final String key, final String val ) {
    1605                if( key != null && val != null ) {                      // ConcurrentMap なので。
    1606                        rtnMap.put( key, val );
    1607                }
    1608        }
    1609
    1610        /**
    1611         * 変数に関連付けた値を、返します。
    1612         * これは、BizLogicから、呼び出し元のJSPに、RETURN 変数以外の {&#064;XXXX} ﾊﾟﾗﾒｰﾀを返します。
    1613         * 既存のｱﾄﾘﾋﾞｭｰﾄがあれば、上書きされます。
    1614         *
    1615         * @og.rev 6.9.9.0 (2018/08/20) 戻り値を返せるようにします。
    1616         *
    1617         * @return      内部ﾏｯﾌﾟｵﾌﾞｼﾞｪｸﾄ
    1618         */
    1619        protected final Map<String,String> getReturnMap() {
    1620                return rtnMap;
    1621        }
    1622}