    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.hayabusa.taglib;
    017
    018import org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.HybsSystemException;
    020import org.opengion.hayabusa.db.DBConstValue;
    021
    022import org.opengion.fukurou.util.StringUtil ;
    023import static org.opengion.fukurou.util.StringUtil.nval ;
    024
    025import java.util.Map;
    026import java.util.LinkedHashMap;
    027
    028/**
    029 * TableUpdateTag にパラメーターを渡す為のタグクラスです。
    030 *
    031 * 汎用的なデータベース登録処理を行えるタグ tableUpdate タグを新規作成します。
    032 * これは、具体的なSLQを作成する tableUpdateParam タグと組み合わせて使用できます。
    033 * tableUpdate タグは、queryType に JDBCTableUpdate を指定します。基本的にこれだけ
    034 * です。tableUpdateParam では、sqlType に、INSERT,COPY,UPDATE,MODIFY,DELETE の
    035 * どれかを指定する事で、SQL文のタイプを指定します。COPY,MODIFY は command と
    036 * 関連を持たす為に追加しているタイプで、INSERTやUPDATE と同じ処理を行います。
    037 * tableUpdateParam の table には、作成したい SQL のテーブルを指定します。
    038 * where 属性は、検索結果の DBTableModel の更新時に使用する条件を指定します。
    039 *
    040 * @og.formSample
    041 * ●形式：&lt;og:tableUpdate command="{&#064;command}" queryType="JDBCTableUpdate" &gt;
    042 *            &lt;og:tableUpdateParam
    043 *                sqlType       = "{&#064;sqlType}"       // INSERT,COPY,UPDATE,MODIFY,DELETE
    044 *                table         = "{&#064;TABLE_NAME}"    // 処理対象のテーブル名
    045 *                names         = "{&#064;names}"         // 処理対象のカラム名
    046 *                omitNames     = "{&#064;omitNames}"     // 処理対象外のカラム名
    047 *                where         = "{&#064;where}"         // 処理対象を特定するキー
    048 *                whereNames    = "{&#064;whereNames}"    // 処理対象を特定するキー条件(where句)をCSV形式
    049 *                constKeys     = "{&#064;constKeys}"     // 処理カラム名の中の固定情報カラム名
    050 *                constVals     = "{&#064;constVals}"     // 処理カラム名の中の固定情報設定値
    051 *                asNames       = "{&#064;asNames}"       // 別名を付けたカラム名(select A as B from TBL の B を指定)
    052 *                orgNames      = "{&#064;orgNames}"      // tableの実際のカラム名(select A as B from TBL の A を指定)
    053 *                funcKeys      = "{&#064;funcKeys}"      // 関数等を設定するカラム名
    054 *                funcVals      = "{&#064;funcVals}"      // 関数等の設定値
    055 *                logicalDelete = "{&#064;logicalDelete}" // sqlTypeがDELETEの場合にもUPDATE文を発行
    056 *            /&gt;
    057 *         &lt;/og:tableUpdate&gt;
    058 *
    059 * ●body：なし
    060 *
    061 * ●Tag定義：
    062 *   &lt;og:tableUpdateParam
    063 *       sqlType          ○【TAG】BODY部に書かれている SQLタイプを指定します(必須)
    064 *       table            ○【TAG】処理対象のテーブル名を指定します(必須)
    065 *       names              【TAG】処理対象のカラム名をCSV形式で複数指定します
    066 *       omitNames          【TAG】処理対象外のカラム名をCSV形式で複数指定します
    067 *       where              【TAG】処理対象を特定するキー条件(where句)を指定します
    068 *       whereNames         【TAG】処理対象を特定するキー条件(where句)をCSV形式で複数指定します
    069 *       constKeys          【TAG】設定値を固定値と置き換える対象となるカラム名をCSV形式で複数指定します
    070 *       constVals          【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します
    071 *       funcKeys           【TAG】関数等を設定するカラム名をCSV形式で複数指定します
    072 *       funcVals           【TAG】関数等の設定値をCSV形式で複数指定します
    073 *       asNames            【TAG】別名を付けたカラム名(select A as B from TBL の B を指定)をCSV形式で複数指定します
    074 *       orgNames           【TAG】tableの実際のカラム名(select A as B from TBL の A を指定)をCSV形式で複数指定します
    075 *       quotCheck          【TAG】リクエスト情報の クォーティション(') 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_SQL_INJECTION_CHECK[=true])
    076 *       constObjKey        【TAG】固定情報カラムの処理オブジェクトを特定するキーを設定します(初期値:SYSTEM_ID)
    077 *       logicalDelete      【TAG】sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します(初期値:false)
    078 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    079 *   /&gt;
    080 *
    081 * ●使用例
    082 *    ・【entry.jsp】
    083 *         &lt;og:tableUpdate command="{&#064;command}" queryType="JDBCTableUpdate" &gt;
    084 *            &lt;og:tableUpdateParam
    085 *               sqlType  = "{&#064;sqlType}"
    086 *               table    = "{&#064;MEM.TABLE_NAME}"
    087 *               where    = "ROWID = [ROWID]"
    088 *            /&gt;
    089 *         &lt;/og:tableUpdate&gt;
    090 *
    091 * @og.rev 3.8.8.0 (2007/12/22) 新規作成
    092 * @og.rev 4.1.2.0 (2008/03/12) 実装の大幅な修正
    093 * @og.group ＤＢ登録
    094 *
    095 * @version  4.0
    096 * @author   Kazuhiko Hasegawa
    097 * @since    JDK5.0,
    098 */
    099public class TableUpdateParamTag extends CommonTagSupport {
    100        //* このプログラムのVERSION文字列を設定します。   {@value} */
    101        private static final String VERSION = "5.5.8.5 (2012/11/27)" ;
    102
    103        private static final long serialVersionUID = 558520121127L ;    // 5.5.8.5 (2012/11/27)
    104
    105        /** sqlType属性に設定できる値                    {@value} */
    106        public static final String SQL_TYPE  = "|INSERT|COPY|UPDATE|MODIFY|DELETE|" ;
    107
    108        // 3.8.0.4 (2005/08/08) 印刷時に使用するシステムID
    109        private static final String SYSTEM_ID =HybsSystem.sys( "SYSTEM_ID" );
    110
    111        // 4.3.6.0 (2009/05/01) デフォルトで利用するconstObjのシステムリソース名
    112        private static final String DEFAULT_CONST_OBJ = HybsSystem.sys( "DEFAULT_CONST_CLASS" );
    113
    114        private String          sqlType         = null;                 // INSERT,COPY,UPDATE,MODIFY,DELETE
    115        private String          table           = null;                 // 処理対象のテーブル名
    116        private String[]        names           = null;                 // 処理対象のカラム名
    117        private String          omitNames       = ",ROWID,ROWNUM,WRITABLE,";            // 処理対象外のカラム名
    118        private String          where           = null;                 // 処理対象を特定するキー
    119        private String          whereNames      = null;                 // 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のカラム名
    120        private String[]        constKeys       = null;                 // 処理カラム名の中の固定情報カラム名
    121        private String[]        constVals       = null;                 // 処理カラム名の中の固定情報設定値
    122        private String[]        funcKeys        = null;                 // 5.5.1.9 (2012/04/19) 関数等を設定するカラム名
    123        private String[]        funcVals        = null;                 // 5.5.1.9 (2012/04/19) 関数等の設定値
    124        private String[]        asNames         = null;                 // 5.5.1.9 (2012/04/19) 別名を付けたカラム名(select A as B from TBL の B を指定)
    125        private String[]        orgNames        = null;                 // 5.5.1.9 (2012/04/19) tableの実際のカラム名(select A as B from TBL の A を指定)
    126        private String          constObjKey     = SYSTEM_ID;    // 固定情報カラムの処理オブジェクトを特定するキー
    127        private boolean         quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );
    128        private boolean         logicalDelete = false;          // 4.3.7.0 (2009/06/01) sqlTypeがDELETEの場合にもUPDATE文を発行
    129
    130        /**
    131         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    132         *
    133         * @og.rev 5.5.1.9 (2012/04/19) エラーチェックを先に行います。
    134         *
    135         * @return      後続処理の指示( SKIP_BODY )
    136         */
    137        @Override
    138        public int doStartTag() {
    139
    140                // constKeys,constVals の個数チェック
    141                if( constKeys != null ) {
    142                        if( constVals == null || constKeys.length != constVals.length ) {
    143                                String errMsg = "<b>constKeys と、constVals の個数が異なります。</b><br />"
    144                                                                        + " constKeys=[" + StringUtil.array2csv( constKeys ) + "]"
    145                                                                        + " constVals=[" + StringUtil.array2csv( constVals ) + "]" ;
    146                                throw new HybsSystemException( errMsg );
    147                        }
    148                }
    149
    150                // funcKeys,funcVals の個数チェック
    151                if( funcKeys != null ) {
    152                        if( funcVals == null || funcKeys.length != funcVals.length ) {
    153                                String errMsg = "<b>funcKeys と、funcVals の個数が異なります。</b><br />"
    154                                                                        + " funcKeys=[" + StringUtil.array2csv( funcKeys ) + "]"
    155                                                                        + " funcVals=[" + StringUtil.array2csv( funcVals ) + "]" ;
    156                                throw new HybsSystemException( errMsg );
    157                        }
    158                }
    159
    160                // asNames,orgNames の個数チェック
    161                if( orgNames != null ) {
    162                        if( asNames == null || orgNames.length != asNames.length ) {
    163                                String errMsg = "<b>orgNames と、asNames の個数が異なります。</b><br />"
    164                                                                        + " orgNames=[" + StringUtil.array2csv( orgNames ) + "]"
    165                                                                        + " asNames=[" + StringUtil.array2csv( asNames ) + "]" ;
    166                                throw new HybsSystemException( errMsg );
    167                        }
    168                }
    169
    170                return(SKIP_BODY);                              // Body を評価しない
    171        }
    172
    173        /**
    174         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    175         *
    176         * @og.rev 4.3.7.0 (2009/06/01) 論理削除対応
    177         *
    178         * @return      後続処理の指示
    179         */
    180        @Override
    181        public int doEndTag() {
    182                debugPrint();
    183
    184                TableUpdateTag updateTag = (TableUpdateTag)findAncestorWithClass( this,TableUpdateTag.class );
    185                if( updateTag == null ) {
    186//                      String errMsg = "<b>このタグは、TableUpdateTagの内側(要素)に記述してください。</b>";
    187                        String errMsg = "<b>" + getTagName() + "タグは、TableUpdateTagの内側(要素)に記述してください。</b>";
    188                        throw new HybsSystemException( errMsg );
    189                }
    190
    191                String upSqlType = updateTag.getSqlType() ;
    192                if( upSqlType == null || upSqlType.equals( sqlType ) ) {
    193                        // 通常の names カラム配列を設定します。
    194                        if( names == null ) { names = updateTag.getNames(); }
    195                        NamesData namesData = makeNamesData( names );
    196
    197                        String query = null;
    198                        if( "INSERT".equalsIgnoreCase( sqlType ) || "COPY".equalsIgnoreCase( sqlType ) ) {
    199                                query = getInsertSQL( namesData );
    200                        }
    201                        else if( "UPDATE".equalsIgnoreCase( sqlType ) || "MODIFY".equalsIgnoreCase( sqlType )
    202                                        || ( "DELETE".equalsIgnoreCase( sqlType ) && logicalDelete ) ) { // 4.3.7.0 (2009/06/01)
    203                                query = getUpdateSQL( namesData );
    204                        }
    205                        else if( "DELETE".equalsIgnoreCase( sqlType ) ) {
    206                                query = getDeleteSQL();
    207                        }
    208
    209                        jspPrint( query );
    210                }
    211
    212                return(EVAL_PAGE);
    213        }
    214
    215        /**
    216         * タグリブオブジェクトをリリースします。
    217         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    218         *
    219         * @og.rev 4.3.7.0 (2009/06/01) logicalDelete属性追加
    220         * @og.rev 5.5.1.9 (2012/04/19) asNames、orgNames、funcKeys、funcVals属性追加
    221         * @og.rev 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のカラム名
    222         */
    223        @Override
    224        protected void release2() {
    225                super.release2();                       // 3.5.6.0 (2004/06/18) 追加(抜けていた)
    226                sqlType         = null;                 // INSERT,COPY,UPDATE,MODIFY,DELETE
    227                table           = null;                 // 処理対象のテーブル名
    228                names           = null;                 // 処理対象のカラム名
    229                omitNames       = ",ROWID,ROWNUM,WRITABLE,";            // 処理対象外のカラム名
    230                where           = null;                 // 処理対象を特定するキー
    231                whereNames      = null;                 // 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のカラム名
    232                constKeys       = null;                 // 処理カラム名の中の固定情報カラム名
    233                constVals       = null;                 // 処理カラム名の中の固定情報設定値
    234                quotCheck       = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" );
    235                constObjKey     = SYSTEM_ID;    // 固定情報カラムの処理オブジェクトを特定するキー
    236                logicalDelete = false;          // 4.3.7.0 (2009/06/01)
    237                funcKeys        = null;                 // 5.5.1.9 (2012/04/19) 関数等を設定するカラム名
    238                funcVals        = null;                 // 5.5.1.9 (2012/04/19) 関数等の設定値
    239                asNames         = null;                 // 5.5.1.9 (2012/04/19) 別名を付けたカラム名(select A as B from TBL の B を指定)
    240                orgNames        = null;                 // 5.5.1.9 (2012/04/19) tableの実際のカラム名(select A as B from TBL の A を指定)
    241        }
    242
    243        /**
    244         * 【TAG】BODY部に書かれている SQLタイプを指定します。
    245         *
    246         * @og.tag
    247         * SQLタイプは、INSERT,COPY,UPDATE,MODIFY,DELETE の中から指定する
    248         * 必要があります。これらは、内部に書かれるSQLの形式を指定するのに使用します。
    249         * 内部処理は、DBTableModelの改廃コード(A,C,D)に対して使用される
    250         * SQL を選択する場合の情報に使用されます。
    251         * なお、COPY と MODIFY は、command で指定できる簡易機能として用意しています。
    252         * 上位の TableUpdateTag の sqlType 属性 と同じsqlType 属性の場合のみ、SQL文を
    253         * 合成・出力します。(上位のsqlTypeがnullの場合は、無条件実行します。)
    254         * 指定のタイプが、異なる場合は、なにも処理を行いません。
    255         *
    256         * @param       type BODY部に書かれている SQL タイプ
    257         */
    258        public void setSqlType( final String type ) {
    259                sqlType = nval( getRequestParameter( type ),sqlType );
    260                if( sqlType != null && SQL_TYPE.indexOf( "|" + sqlType + "|" ) < 0 ) {
    261                        sqlType = null;
    262        //              String errMsg = "sqlType属性には、" + SQL_TYPE + "以外設定できません。"
    263        //                                      + " typeIn=[" + type + "]"
    264        //                                      + " sqlType=[" + sqlType + "]" ;
    265        //              throw new HybsSystemException( errMsg );
    266                }
    267        }
    268
    269        /**
    270         * 【TAG】処理対象のテーブル名を指定します。
    271         *
    272         * @og.tag
    273         * テーブル名を指定することで、sqlTypeに応じた QUERYを生成することが出来ます。
    274         * 生成する場合のカラムを特定する場合は、names 属性で指定できます。
    275         * また、WHERE条件は、where属性で指定します。
    276         *
    277         * @param       tbl テーブル名
    278         * @see         #setNames( String )
    279         * @see         #setWhere( String )
    280         * @see         #setSqlType( String )
    281         */
    282        public void setTable( final String tbl ) {
    283                table = nval( getRequestParameter( tbl ),table );
    284        }
    285
    286        /**
    287         * 【TAG】処理対象のカラム名をCSV形式で複数指定します。
    288         *
    289         * @og.tag
    290         * 生成するQUERYのカラム名をカンマ区切り文字(CSV)で複数指定します。
    291         * 指定がない場合は、DBTableModel の全カラム(※)を使用して、QUERYを構築します。
    292         * 一般に、テーブル結合してDBTableModelを構築した場合は、登録すべきカラムを
    293         * 指定する必要があります。
    294         * (※)正確には、DBTableModel の全カラムのうち、ROWID,ROWNUM,WRITABLE カラムは
    295         * 無視します。
    296         * 分解方法は、通常のパラメータ取得後に、CSV分解します。
    297         *
    298         * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。
    299         *
    300         * @param       nms カラム名(CSV形式)
    301         * @see         #setTable( String )
    302         * @see         #setOmitNames( String )
    303         */
    304        public void setNames( final String nms ) {
    305                names = StringUtil.csv2Array( getRequestParameter( nms ) );
    306                if( names.length == 0 ) { names = null; }
    307        }
    308
    309        /**
    310         * 【TAG】処理対象外のカラム名をCSV形式で複数指定します。
    311         *
    312         * @og.tag
    313         * 生成するQUERYのカラム名に指定しないカラム名をカンマ区切り文字(CSV)で複数指定します。
    314         * 指定がない場合は、DBTableModel の全カラム(※)を使用して、QUERYを構築します。
    315         * テーブル結合などで、処理したくないカラム数の方が少ない場合に、names ですべてを
    316         * 指定するより少ない記述ですみます。
    317         * (※)正確には、DBTableModel の全カラムのうち、ROWID,ROWNUM,WRITABLE カラムは
    318         * 無視します。
    319         *
    320         * @param       nms カラム名(CSV形式)
    321         * @see         #setTable( String )
    322         * @see         #setNames( String )
    323         */
    324        public void setOmitNames( final String nms ) {
    325                omitNames = omitNames + nval( getRequestParameter( nms ),"" ) + ",";
    326        }
    327
    328        /**
    329         * 【TAG】処理対象を特定するキー条件(where句)を指定します。
    330         *
    331         * @og.tag
    332         * 生成するQUERYのwhere 句を指定します。通常の WHERE 句の書き方と同じで、
    333         * DBTableModelの値を割り当てたい箇所に[カラム名] を記述します。
    334         * 文字列の場合、設定値をセットするときに、シングルコーテーションを
    335         * 使用しますが、[カラム名]で指定する場合は、その前後に、(')シングル
    336         * コーテーションは、不要です。
    337         * {&#064;XXXX}変数を使用する場合は、パース時に固定文字に置き換えられる為、
    338         * 文字列指定時の(')シングルコーテーションが必要になります。
    339         * ※ 5.5.8.5 (2012/11/27) whereNames 属性と併用した場合は、where が、and を付けて、文字列結合されます。
    340         * 例：FGJ='1' and CLM=[CLM] and SYSTEM_ID in ([SYSID],'**') and KBSAKU='{&#064;KBSAKU}'
    341         *
    342         * @param       wr 検索条件(where句)
    343         */
    344        public void setWhere( final String wr ) {
    345                where = nval( getRequestParameter( wr ),where );
    346        }
    347
    348        /**
    349         * 【TAG】処理対象を特定するキー条件(where句)をCSV形式で複数指定します。
    350         *
    351         * @og.tag
    352         * 生成するQUERYのwhere 句を指定する方法として、複数のカラム名をCSV指定し、内部で
    353         * KEY=[KEY] 文字列を作成します。
    354         * ここでは、カラム名は、データベースのカラム名と同じで、かつ、DBTableModel にも
    355         * 同じカラムのデータが存在していること、という条件付きとします。
    356         * また、where 条件との併用を行いますが、こちらの条件が先に使用され、where 条件は、
    357         * and を付けて、文字列結合されます。
    358         * 例： CLM,SYSTEM_ID,KBSAKU   ⇒   CLM=[CLM] and SYSTEM_ID=[SYSTEM_ID] and KBSAKU=[KBSAKU]
    359         *
    360         * @og.rev 5.5.8.5 (2012/11/27) 新規追加
    361         *
    362         * @param       wrnm 検索条件(where句)作成のためのカラム名(CSV形式)
    363         */
    364        public void setWhereNames( final String wrnm ) {
    365                whereNames = nval( getRequestParameter( wrnm ),whereNames );
    366        }
    367
    368        /**
    369         * 【TAG】設定値を固定値と置き換える対象となるカラム名をCSV形式で複数指定します。
    370         *
    371         * @og.tag
    372         * names 属性のカラムや table 属性より、QUERYを作成して、DBTableModelの値を
    373         * 割り当てる場合、DBTableModelの値ではなく、外部から指定した固定値を
    374         * 割り当てたい場合に、そのカラム名をカンマ区切り文字(CSV)で複数指定します。
    375         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    376         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    377         *
    378         * @param       keys カラム名(CSV形式)
    379         * @see         #setConstVals( String )
    380         */
    381        public void setConstKeys( final String keys ) {
    382                constKeys = getCSVParameter( keys );
    383        }
    384
    385        /**
    386         * 【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します。
    387         *
    388         * @og.tag
    389         * names 属性のカラムや table 属性より、QUERYを作成して、DBTableModelの
    390         * 値を割り当てる場合、DBTableModelの値ではなく、外部から指定した固定値を
    391         * 割り当てたい場合に、そのカラム名に対応する設定値をカンマ区切り文字(CSV)で
    392         * 複数指定します。ここで指定する設定値は、constKeys 属性と対応させます。
    393         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    394         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    395         *
    396         * @param       vals 設定値(CSV形式)
    397         * @see         #setConstKeys( String )
    398         */
    399        public void setConstVals( final String vals ) {
    400                constVals = getCSVParameter( vals );
    401        }
    402
    403        /**
    404         * 【TAG】関数等を設定するカラム名をCSV形式で複数指定します。
    405         *
    406         * @og.tag
    407         * constVals 属性で設定する値は、必ずシングルクオートが付与されます。
    408         * その場合、関数などを設定したい場合でも、文字列として設定しようとします。
    409         * ここで指定するカラム名(funcKeys)自身は、constKeys と同じ書式です。
    410         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    411         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    412         *
    413         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    414         *
    415         * @param       keys カラム名(CSV形式)
    416         * @see         #setFuncVals( String )
    417         */
    418        public void setFuncKeys( final String keys ) {
    419                funcKeys = getCSVParameter( keys );
    420        }
    421
    422        /**
    423         * 【TAG】関数等の設定値をCSV形式で複数指定します。
    424         *
    425         * @og.tag
    426         * funcKeys 属性に対応する 関数などの設定値を割り当てます。
    427         * constVals 属性との違いは、funcVals の設定値は、そのままの形で、SQL文の
    428         * 構築に使われます。
    429         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    430         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    431         *
    432         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    433         *
    434         * @param       vals 設定値(CSV形式)
    435         * @see         #setFuncKeys( String )
    436         */
    437        public void setFuncVals( final String vals ) {
    438                funcVals = getCSVParameter( vals );
    439        }
    440
    441        /**
    442         * 【TAG】別名を付けたカラム名(select A as B from TBL の B を指定)をCSV形式で複数指定します。
    443         *
    444         * @og.tag
    445         * SELECT 文を記述したとき、別名を付けていたり、SELECTしたテーブルと別のテーブルに
    446         * DBTableModelの値を書き込む場合、DBTableModel の持っているカラム名と、実際に
    447         * 書き込むカラム名が異なります。そのようなケースに、元の別名カラムを指定します。
    448         * orgNames属性の並び順と、asNames属性の並び順を合わせておく必要があります。
    449         * このカラム名は、DBTableModel には持っているが、テーブル側には持っていない値
    450         * なので、内部的に omitNames 属性に値を設定します。利用者は、omitNames に
    451         * 書き込む必要はありません。
    452         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    453         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    454         *
    455         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    456         *
    457         * @param       keys カラム名(CSV形式)
    458         * @see         #setOrgNames( String )
    459         */
    460        public void setAsNames( final String keys ) {
    461                asNames = getCSVParameter( keys );
    462        }
    463
    464        /**
    465         * 【TAG】tableの実際のカラム名(select A as B from TBL の A を指定)をCSV形式で複数指定します。
    466         *
    467         * @og.tag
    468         * SELECT 文を記述したとき、別名を付けていたり、SELECTしたテーブルと別のテーブルに
    469         * DBTableModelの値を書き込む場合、DBTableModel の持っているカラム名と、実際に
    470         * 書き込むカラム名が異なります。そのようなケースに、テーブルの実カラムを指定します。
    471         * orgNames属性の並び順と、asNames属性の並び順を合わせておく必要があります。
    472         * このカラム名は、DBTableModel には持っていませんが、テーブル側には持っている値
    473         * なので、このカラム名で、SQL文を構築します。 UPDATE TBL SET A=[B] WHERE … となります。
    474         * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。
    475         * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。
    476         *
    477         * @og.rev 5.5.1.9 (2012/04/19) 新規追加
    478         *
    479         * @param       keys カラム名(CSV形式)
    480         * @see         #setAsNames( String )
    481         */
    482        public void setOrgNames( final String keys ) {
    483                orgNames = getCSVParameter( keys );
    484        }
    485
    486        /**
    487         * 【TAG】リクエスト情報の クォーティション(') 存在チェックを実施するかどうか[true/false]を設定します
    488         *              (初期値:USE_SQL_INJECTION_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK}])。
    489         *
    490         * @og.tag
    491         * ＳＱＬインジェクション対策の一つとして、暫定的ではありますが、SQLのパラメータに
    492         * 渡す文字列にクォーティション(') を許さない設定にすれば、ある程度は防止できます。
    493         * 数字タイプの引数には、 or 5=5 などのクォーティションを使用しないコードを埋めても、
    494         * 数字チェックで検出可能です。文字タイプの場合は、必ず (')をはずして、
    495         * ' or 'A' like 'A のような形式になる為、(')チェックだけでも有効です。
    496         * (') が含まれていたエラーにする(true)／かノーチェックか(false)を指定します。
    497         * (初期値:システム定数のUSE_SQL_INJECTION_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK}])。
    498         *
    499         * @param   flag クォーティションチェック [true:する/それ以外:しない]
    500         * @see         org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK
    501         */
    502        public void setQuotCheck( final String flag ) {
    503                quotCheck = nval( getRequestParameter( flag ),quotCheck );
    504        }
    505
    506        /**
    507         * 【TAG】固定情報カラムの処理オブジェクトを特定するキーを設定します(初期値:SYSTEM_ID)。
    508         *
    509         * @og.tag
    510         * 固定情報カラム をシステム単位にJavaクラスで管理できます。
    511         * そのクラスオブジェクトは、org.opengion.hayabusa.db.DBConstValue インターフェースを
    512         * 継承した、plugin クラスになります。
    513         * そのクラスを特定するキーワードを指定します。
    514         * 初期値は、SYSTEM_ID でシステム単位にクラスを作成します。
    515         * もし、他のシステムと共通の場合は、継承だけさせることも可能です。
    516         * 対応したDBConstValueクラスがプラグインとして存在しない場合は、
    517         * システムリソースのDEFAULT_CONST_CLASSで指定されたクラスが利用されます。
    518         *
    519         * 初期値は、SYSTEM_ID です。
    520         *
    521         * @param   key 固定情報カラムの処理オブジェクトを特定するキー
    522         */
    523        public void setConstObjKey( final String key ) {
    524                constObjKey = nval( getRequestParameter( key ),constObjKey );
    525        }
    526
    527        /**
    528         * 【TAG】sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します(初期値:false)。
    529         *
    530         * @og.tag
    531         * sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します。
    532         * trueが指定された場合は、DELETE文ではなく、UPDATE文が発行されます。
    533         * falseが指定された場合は、DELETE文が発行されます。
    534         * さらに論理削除を行う場合、org.opengion.hayabusa.db.DBConstValue インターフェースに
    535         * 定義されている、getLogicalDeleteKeys()及びgetLogicalDeleteValsを実装することで、
    536         * 論理削除する際のフラグの更新方法を統一的に管理することが可能になります。
    537         * 初期値は、false(物理削除する)です
    538         *
    539         * @param   flg 論理削除(UPDATE)を行うかどうか
    540         */
    541        public void setLogicalDelete( final String flg ) {
    542                logicalDelete = nval( getRequestParameter( flg ),logicalDelete );
    543        }
    544
    545        /**
    546         * データをインサートする場合に使用するSQL文を作成します。
    547         *
    548         * @og.rev 4.1.2.1 (2008/03/17) DBConstValue による固定値セットを採用
    549         * @og.rev 4.3.6.4 (2009/05/01) デフォルト設定をシステムリソースで設定可能にする
    550         * @og.rev 5.3.4.0 (2011/04/01) DEFAULT_CONST_OBJの初期値変更(null→ゼロ文字列)
    551         *
    552         * @param   namesData NamesDataオブジェクト
    553         *
    554         * @return  インサートSQL
    555         */
    556        private String getInsertSQL( final NamesData namesData ) {
    557                String cls = HybsSystem.sys( "DBConstValue_" + constObjKey ) ;
    558
    559                // 4.3.6.4 (2009/05/01) 標準の追加
    560                if( cls == null){
    561                        cls = DEFAULT_CONST_OBJ;
    562                }
    563
    564//              if( cls != null ) {             // 5.3.4.0 (2011/04/01)
    565                if( cls != null && !cls.isEmpty() ) {
    566                        DBConstValue constVal = (DBConstValue)HybsSystem.newInstance( cls );
    567                        // 4.2.1.0 (2008/04/16) 初期化追加
    568                        constVal.init( table,getUser().getUserID(),getGUIInfoAttri( "KEY" ) );
    569                        String[] keys = constVal.getInsertKeys();
    570                        String[] vals = constVal.getInsertVals();
    571                        namesData.add( keys,vals );
    572                }
    573
    574                String[] nms = namesData.getNames();
    575                String[] vls = namesData.getVals();
    576
    577                StringBuilder sql = new StringBuilder();
    578                sql.append( "INSERT INTO " ).append( table );
    579                sql.append( " ( " );
    580                sql.append( nms[0] );
    581                for( int i=1; i<nms.length; i++ ) {
    582                        sql.append( "," ).append( nms[i] );
    583                }
    584                sql.append( " ) VALUES ( " );
    585                sql.append( vls[0] );
    586                for( int i=1; i<vls.length; i++ ) {
    587                        sql.append( "," ).append( vls[i] );
    588                }
    589                sql.append( " )" );
    590
    591                return sql.toString();
    592        }
    593
    594        /**
    595         * データをアップデートする場合に使用するSQL文を作成します。
    596         *
    597         * where と whereNames が同時に指定された場合は、whereNames が先に処理され
    598         * where 条件は、and 結合されます。
    599         *
    600         * @og.rev 4.1.2.1 (2008/03/17) DBConstValue による固定値セットを採用
    601         * @og.rev 4.3.6.4 (2009/05/01) デフォルト設定をシステムリソースで設定可能にする
    602         * @og.rev 4.3.7.0 (2009/06/01) 論理削除対応
    603         * @og.rev 5.3.7.0 (2011/07/01) DEFAULT_CONST_OBJの初期値変更(null→ゼロ文字列) 対応忘れ
    604         * @og.rev 5.5.8.5 (2012/11/27) whereNames 対応
    605         *
    606         * @param   namesData NamesDataオブジェクト
    607         *
    608         * @return  アップデートSQL
    609         */
    610        private String getUpdateSQL( final NamesData namesData ) {
    611                String cls = HybsSystem.sys( "DBConstValue_" + constObjKey ) ;
    612
    613                // 4.3.6.4 (2009/05/01) 標準の追加
    614                if( cls == null){
    615                        cls = DEFAULT_CONST_OBJ;
    616                }
    617
    618//              if( cls != null ) {
    619                if( cls != null && !cls.isEmpty() ) {           // 5.3.7.0 (2011/07/01)
    620                        DBConstValue constVal = (DBConstValue)HybsSystem.newInstance( cls );
    621                        // 4.2.1.0 (2008/04/16) 初期化追加
    622                        constVal.init( table,getUser().getUserID(),getGUIInfoAttri( "KEY" ) );
    623                        // 4.3.7.0 (2009/06/01) 論理削除対応
    624                        String[] keys = null;
    625                        String[] vals = null;
    626                        if( "DELETE".equalsIgnoreCase( sqlType ) ) {
    627                                keys = constVal.getLogicalDeleteKeys();
    628                                vals = constVal.getLogicalDeleteVals();
    629                        }
    630                        else {
    631                                keys = constVal.getUpdateKeys();
    632                                vals = constVal.getUpdateVals();
    633                        }
    634                        namesData.add( keys,vals );
    635                }
    636
    637                String[] nms = namesData.getNames();
    638                String[] vls = namesData.getVals();
    639
    640                StringBuilder sql = new StringBuilder();
    641                sql.append( "UPDATE " ).append( table ).append( " SET " );
    642                sql.append( nms[0] ).append( "=" ).append( vls[0] );
    643
    644                for( int i=1; i<nms.length; i++ ) {
    645                        sql.append( "," );
    646                        sql.append( nms[i] ).append( "=" ).append( vls[i] );
    647                }
    648
    649                // 5.5.8.5 (2012/11/27) whereNames 対応
    650                String whereAnd = " WHERE " ;
    651                if( whereNames != null && whereNames.length() > 0 ) {
    652                        String[] wnms = whereNames.split(",");
    653                        sql.append( whereAnd ).append( wnms[0] ).append( "=[" ).append( wnms[0] ).append( "]" );
    654
    655                        for( int i=1; i<wnms.length; i++ ) {
    656                                sql.append( " AND " ).append( wnms[i] ).append( "=[" ).append( wnms[i] ).append( "]" );
    657                        }
    658                        whereAnd = " AND " ;            // whereNames 優先。ここを通らなければ、初期値のまま、" WHERE " が使われる
    659                }
    660
    661                // 5.5.8.5 (2012/11/27) whereNames 対応。whereNames が登録されていれば、AND で繋げる。
    662                if( where != null && where.length() > 0 ) {
    663//                      sql.append( " WHERE " ).append( where );
    664                        sql.append( whereAnd ).append( where );
    665                }
    666
    667                return sql.toString();
    668        }
    669
    670        /**
    671         * データをデリートする場合に使用するSQL文を作成します。
    672         *
    673         * where と whereNames が同時に指定された場合は、whereNames が先に処理され
    674         * where 条件は、and 結合されます。
    675         *
    676         * @og.rev 5.5.8.5 (2012/11/27) whereNames 対応
    677         *
    678         * @return  デリートSQL
    679         */
    680        private String getDeleteSQL() {
    681                StringBuilder sql = new StringBuilder();
    682                sql.append( "DELETE FROM " ).append( table );
    683
    684                // 5.5.8.5 (2012/11/27) whereNames 対応
    685                String whereAnd = " WHERE " ;
    686                if( whereNames != null && whereNames.length() > 0 ) {
    687                        String[] wnms = whereNames.split(",");
    688                        sql.append( whereAnd ).append( wnms[0] ).append( "=[" ).append( wnms[0] ).append( "]" );
    689
    690                        for( int i=1; i<wnms.length; i++ ) {
    691                                sql.append( " AND " ).append( wnms[i] ).append( "=[" ).append( wnms[i] ).append( "]" );
    692                        }
    693                        whereAnd = " AND " ;            // whereNames 優先。ここを通らなければ、初期値のまま、" WHERE " が使われる
    694                }
    695
    696                // 5.5.8.5 (2012/11/27) whereNames 対応。whereNames が登録されていれば、AND で繋げる。
    697                if( where != null && where.length() > 0 ) {
    698//                      sql.append( " WHERE " ).append( where );
    699                        sql.append( whereAnd ).append( where );
    700                }
    701                return sql.toString();
    702        }
    703
    704        /**
    705         * names,constKeys,omitNames から、必要なキー情報と、属性情報を持った NamesData を作成します。
    706         *
    707         * @og.rev 4.1.2.1 (2008/03/17) 固定値の constVals の前後に、"'" を入れる。
    708         * @og.rev 5.5.1.9 (2012/04/19) asNames、orgNames、funcKeys、funcVals属性追加
    709         *
    710         * @param   nms カラム名配列
    711         *
    712         * @return      属性情報を持ったNamesData
    713         */
    714        private NamesData makeNamesData( final String[] nms ) {
    715
    716                NamesData namesData = new NamesData();
    717
    718                // 5.5.1.9 (2012/04/19) omitNames に、asNames配列の値を設定しておきます。
    719                if( asNames != null ) {
    720                        for( int i=0; i<asNames.length; i++ ) {
    721                                if( asNames[i] != null && asNames[i].length() > 0 ) {
    722                                        omitNames = omitNames + asNames[i] + ",";
    723                                }
    724                        }
    725                }
    726
    727                // names で指定されたカラム名
    728                for( int i=0; i<nms.length; i++ ) {
    729                        String nm = nms[i];
    730                        if( nm != null && nm.length() > 0 && omitNames.indexOf( "," + nm + "," ) < 0 ) {
    731                                namesData.add( nm,"[" + nm + "]" ) ;
    732                        }
    733                }
    734
    735                // 固定値の constKeys カラム配列を設定します。
    736                if( constKeys != null && constKeys.length > 0 ) {
    737                        for( int j=0; j<constKeys.length; j++ ) {
    738                                String nm = constKeys[j];
    739                                if( nm != null && nm.length() > 0 ) {
    740                                        namesData.add( nm,"'" + constVals[j] + "'" ) ;  // constVals は、シングルクオートで囲います。
    741                                }
    742                        }
    743                }
    744
    745                // 関数値の funcKeys カラム配列を設定します。
    746                if( funcKeys != null && funcKeys.length > 0 ) {
    747                        for( int j=0; j<funcKeys.length; j++ ) {
    748                                String nm = funcKeys[j];
    749                                if( nm != null && nm.length() > 0 ) {
    750                                        namesData.add( nm, funcVals[j] ) ;              // funcVals は、シングルクオートで囲いません。
    751                                }
    752                        }
    753                }
    754
    755                // 別名の asNames,orgNames カラム配列を設定します。
    756                if( orgNames != null && orgNames.length > 0 ) {
    757                        for( int j=0; j<orgNames.length; j++ ) {
    758                                String onm = orgNames[j];
    759                                if( onm != null && onm.length() > 0 ) {
    760                                        namesData.add( onm,"[" + asNames[j] + "]" ) ;
    761                                }
    762                        }
    763                }
    764
    765                return namesData ;
    766        }
    767
    768        /**
    769         * 内部データを受け渡す為の、簡易クラスです。
    770         * 更新するカラム名と値のセット配列を管理しています。
    771         *
    772         */
    773        private static class NamesData {
    774                final Map<String,String> data = new LinkedHashMap<String,String>() ;
    775
    776                /**
    777                 * キーと値のセットを追加します。
    778                 *
    779                 * @param   nm String
    780                 * @param   val String
    781                 */
    782                public void add( final String nm,final String val ) {
    783                        data.put( nm,val );
    784                }
    785
    786                /**
    787                 * キー配列と対応する、値配列のセットを追加します。
    788                 *
    789                 * @param   nms String[]
    790                 * @param   vals String[]
    791                 */
    792                public void add( final String[] nms,final String[] vals ) {
    793                        if( nms != null ) {
    794                                for( int i=0; i<nms.length; i++ ) {
    795                                        data.put( nms[i],vals[i] );
    796                                }
    797                        }
    798                }
    799
    800                /**
    801                 * キー配列を返します。
    802                 *
    803                 * @return   String[]
    804                 */
    805                public String[] getNames() {
    806                        return data.keySet().toArray( new String[data.size()] );
    807                }
    808
    809                /**
    810                 * 値配列を返します。
    811                 *
    812                 * @return   String[]
    813                 */
    814                public String[] getVals()  {
    815                        return data.values().toArray( new String[data.size()] );
    816                }
    817        }
    818
    819        /**
    820         * このオブジェクトの文字列表現を返します。
    821         * 基本的にデバッグ目的に使用します。
    822         *
    823         * @return このクラスの文字列表現
    824         */
    825        @Override
    826        public String toString() {
    827                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
    828                                .println( "VERSION"                     ,VERSION                )
    829                                .println( "sqlType"                     ,sqlType                )
    830                                .println( "table"                       ,table                  )
    831                                .println( "names"                       ,names                  )
    832                                .println( "omitNames"           ,omitNames              )
    833                                .println( "where"                       ,where                  )
    834                                .println( "whereNames"          ,whereNames             )
    835                                .println( "constKeys"           ,constKeys              )
    836                                .println( "constVals"           ,constVals              )
    837                                .println( "logicalDelete"       ,logicalDelete  )
    838                                .fixForm().toString() ;
    839        }
    840}