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