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