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