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 * ●形式:<og:tableUpdate command="{@command}" queryType="JDBCTableUpdate" >
042 *            <og:tableUpdateParam
043 *                sqlType       = "{@sqlType}"       // INSERT,COPY,UPDATE,MODIFY,DELETE
044 *                table         = "{@TABLE_NAME}"    // 処理対象のテーブル名
045 *                names         = "{@names}"         // 処理対象のカラム名
046 *                omitNames     = "{@omitNames}"     // 処理対象外のカラム名
047 *                where         = "{@where}"         // 処理対象を特定するキー
048 *                whereNames    = "{@whereNames}"    // 処理対象を特定するキー条件(where句)をCSV形式
049 *                constKeys     = "{@constKeys}"     // 処理カラム名の中の固定情報カラム名
050 *                constVals     = "{@constVals}"     // 処理カラム名の中の固定情報設定値
051 *                asNames       = "{@asNames}"       // 別名を付けたカラム名(select A as B from TBL の B を指定)
052 *                orgNames      = "{@orgNames}"      // tableの実際のカラム名(select A as B from TBL の A を指定)
053 *                funcKeys      = "{@funcKeys}"      // 関数等を設定するカラム名
054 *                funcVals      = "{@funcVals}"      // 関数等の設定値
055 *                logicalDelete = "{@logicalDelete}" // sqlTypeがDELETEの場合にもUPDATE文を発行
056 *            />
057 *         </og:tableUpdate>
058 *
059 * ●body:なし
060 *
061 * ●Tag定義:
062 *   <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 *   />
080 *
081 * ●使用例
082 *    ・【entry.jsp】
083 *         <og:tableUpdate command="{@command}" queryType="JDBCTableUpdate" >
084 *            <og:tableUpdateParam
085 *               sqlType  = "{@sqlType}"
086 *               table    = "{@MEM.TABLE_NAME}"
087 *               where    = "ROWID = [ROWID]"
088 *            />
089 *         </og:tableUpdate>
090 *
091 * @og.rev 3.8.8.0 (2007/12/22) 新規作成
092 * @og.rev 4.1.2.0 (2008/03/12) 実装の大幅な修正
093 * @og.group DB登録
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インジェクション対策の一つとして、暫定的ではありますが、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}