    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.DBTableModel;
    021import org.opengion.fukurou.db.DBUtil;
    022
    023import org.opengion.fukurou.util.ErrorMessage;
    024import org.opengion.fukurou.util.StringUtil ;
    025import static org.opengion.fukurou.util.StringUtil.nval ;
    026import org.opengion.fukurou.model.Formatter;
    027
    028import java.util.Locale ;
    029import java.util.List ;
    030import java.util.ArrayList ;
    031
    032import java.io.ObjectOutputStream;
    033import java.io.ObjectInputStream;
    034import java.io.IOException;
    035
    036/**
    037 * 【廃止】登録すべきデータのマスタ存在チェックを行うためのタグです(通常はentry.jspでupdateタグの直前で使用します)。
    038 *
    039 * この要素の内容に、SQL文を記述します。
    040 * names に対応するカラム名を、カンマ区切りで複数与えます。その値を、DBTableModel
    041 * より、取得し、先のSQL文の ? に値を設定します。
    042 * または、引数部に、[カラム名]を用いたHybs拡張SQL文を指定することも可能です。
    043 *
    044 * 値の取得は、先に選択された行のみについて、実行されます。
    045 * exist 属性に指定された 、｢true:存在する｣、｢false:存在しない｣、｢one:ひとつ以下｣、
    046 * の値は、チェック方法を設定しています。
    047 * いずれの場合も、成立時は、正常とみなします。
    048 * (｢true:存在する｣ には、データが存在した場合に、ＯＫで、なければエラーです。)
    049 *
    050 * @og.formSample
    051 * ●形式：
    052 *       ・&lt;og:tableExist
    053 *                    command   = "{&#064;command}"
    054 *                    names     = "[…]"
    055 *                    from      = "…"                           必須
    056 *                    where     = "…"                           必須
    057 *                    exist     = "[auto|true|false|one|notuse]" 必須
    058 *                    errRemove = "[true|false]"
    059 *         /&gt;
    060 *
    061 * ●body：なし
    062 *
    063 * ●Tag定義：
    064 *   &lt;og:tableExist
    065 *       command            【廃止】コマンド(ENTRY)をセットします
    066 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
    067 *       names              【廃止】引数にセットすべき データの名称(カラム名)をCSV形式で複数指定します
    068 *       from             ○【廃止】チェックするデータベース名(from 句)を指定します(必須)。
    069 *       where            ○【廃止】チェックする検索条件(where句)を指定します(必須)。
    070 *       exist              【廃止】データベースのチェック方法(auto/true/false/one/notuse)を指定します(初期値:｢auto:自動｣)
    071 *       tableId            【廃止】(通常は使いません)結果をDBTableModelに書き込んで、sessionに登録するときのキーを指定します
    072 *       dbid               【廃止】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します
    073 *       errRemove          【廃止】エラー時の選択行を取り除いて継続処理を行うかどうか[true/false]を指定します(初期値:false)
    074 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    075 *   /&gt;
    076 *
    077 * ●使用例
    078 *       ・&lt;og:tableExist
    079 *                    command = "{&#064;command}"
    080 *                    names   = "USERID,SYSTEM_ID"
    081 *                    from    = "GE10"
    082 *                    where   = "USERID=? AND SYSTEM_ID=?"
    083 *                    exist   = "true"         /&gt;
    084 *
    085 *          ・where 条件の ? 文字に、names で指定したカラム名の値が、DBTableModelより
    086 *            取得されます。
    087 *            値の取得は、先に選択された行のみについて、実行されます。
    088 *          ・exist 属性の値に応じて、チェック方法が異なります。
    089 *            auto , true , false , one , notuse が指定できます。
    090 *          ・テーブルは、１つのみ指定できます。複数指定や、UNIONで結合する場合は、
    091 *            ビュー等を作成して対応してください。
    092 *
    093 *       ・&lt;og:tableExist
    094 *                    command = "{&#064;command}"
    095 *                    from    = "GE10"
    096 *                    where   = "USERID=[USERID] AND SYSTEM_ID=[SYSTEM_ID]"  /&gt;
    097 *
    098 *          ・where 条件の [カラム名] 文字に、DBTableModelより値がセットされます。
    099 *          ・exist は、初期値(auto)になります。内部のA,C,Dに応じて自動判別します。
    100 *
    101 * @og.rev 3.5.0.0 (2003/09/17) 新規作成
    102 * @og.group (廃止)ＤＢ登録
    103 *
    104 * @version  4.0
    105 * @author       Kazuhiko Hasegawa
    106 * @since    JDK5.0,
    107 * @deprecated 代わりに dataCheckタグを使用してください
    108 */
    109@Deprecated public class TableExistTag extends CommonTagSupport {
    110        //* このプログラムのVERSION文字列を設定します。   {@value} */
    111        private static final String VERSION = "4.0.0.0 (2007/11/28)" ;
    112
    113        private static final long serialVersionUID = 400020071128L ;
    114
    115        /** command 引数に渡す事の出来る コマンド  エントリー {@value} */
    116        public static final String CMD_ENTRY   = "ENTRY" ;
    117
    118        /** command 引数に渡す事の出来る コマンド リスト  */
    119        private static final String COMMAND_LIST = CMD_ENTRY;
    120
    121        // 3.5.6.0 (2004/06/18) すべてを protected から private に変更します。
    122        private transient DBTableModel  table           = null;
    123        private transient ErrorMessage  errMessage      = null;
    124        private String                  tableId         = HybsSystem.TBL_MDL_KEY;
    125        // 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
    126//      private String                  dbid            = "DEFAULT";
    127        private String                  dbid            = null;
    128        private String                  command         = CMD_ENTRY;
    129        private String                  sql                     = null;
    130        private String                  names           = null;
    131        private String                  from            = null;
    132        private String                  where           = null;
    133        private String                  exist           = "auto";
    134        private boolean                 errRemove       = false;
    135
    136        /**
    137         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    138         *
    139         * @og.rev 3.7.1.0 (2005/04/15) notuse 値を追加
    140         *
    141         * @return      後続処理の指示(SKIP_BODY)
    142         */
    143        @Override
    144        public int doStartTag() {
    145                if( !exist.equalsIgnoreCase( "notuse" ) ) {
    146                        table = (DBTableModel)getObject( tableId );
    147                        if( table != null && table.getRowCount() > 0 && check( command, COMMAND_LIST ) ) {
    148                                sql = makeSQLString();
    149                                execute( sql );
    150                        }
    151                }
    152
    153                return(SKIP_BODY);                              // Body を評価しない
    154        }
    155
    156        /**
    157         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    158         *
    159         * @og.rev 3.5.4.2 (2003/12/15) HTMLTableViewForm クラス名変更(⇒ ViewForm_HTMLTable)
    160         * @og.rev 3.5.4.4 (2004/01/16) エラー結果を表示するテーブル形式のフォーム修正
    161         * @og.rev 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
    162         *
    163         * @return      後続処理の指示
    164         */
    165        @Override
    166        public int doEndTag() {
    167                debugPrint();           // 4.0.0 (2005/02/28)
    168
    169                int rtnCode = EVAL_PAGE;
    170
    171                if( CMD_ENTRY.equals( command ) && errMessage != null && ! errMessage.isOK() ) {
    172                // 3.5.5.2 (2004/04/02) TaglibUtil.makeHTMLErrorTable メソッドを利用
    173                        if( !errRemove ) {
    174                                rtnCode = SKIP_PAGE ;
    175                                jspPrint( TaglibUtil.makeHTMLErrorTable( errMessage,getResource() ) );
    176                        }
    177                }
    178
    179                return( rtnCode );
    180        }
    181
    182        /**
    183         * タグリブオブジェクトをリリースします。
    184         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    185         *
    186         * @og.rev 4.0.0.0 (2007/10/10) dbid の初期値を、"DEFAULT" から null に変更
    187         */
    188        @Override
    189        protected void release2() {
    190                super.release2();
    191                tableId                 = HybsSystem.TBL_MDL_KEY;
    192//              dbid                    = "DEFAULT";
    193                dbid                    = null;
    194                command                 = CMD_ENTRY;
    195                table                   = null;
    196                sql                             = null;
    197                names                   = null;
    198                errMessage              = null;
    199                exist                   = "auto";
    200                errRemove               = false;
    201        }
    202
    203        /**
    204         * SQL文を構築します。
    205         *
    206         * @return 構築された、SQL文
    207         */
    208        private String makeSQLString() {
    209                StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
    210                rtn.append( "select count(*) from " );
    211                rtn.append( from );
    212                rtn.append( " where " );
    213                rtn.append( where );
    214
    215                return rtn.toString();
    216        }
    217
    218        /**
    219         * Query を実行します。
    220         *
    221         * @param   sql 検索文字列
    222         *
    223         * @og.rev 3.8.6.0 (2006/09/29) exist 属性の one を ｢one:ひとつのみ｣から｢one:ひとつ以下｣に変更
    224         * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    225         * @og.rev 4.0.0.0 (2005/01/31) getParameterRows() を使用するように変更
    226         * @og.rev 4.0.0.0 (2007/11/28) 論理処理の不具合修正(カッコの付ける位置間違い)
    227         */
    228        private void execute( final String sql ) {
    229                errMessage = new ErrorMessage( "Database Exist Data Error!" );
    230
    231                final String query ;
    232                final int[]  clmNo ;
    233
    234                int[] rowNo = getParameterRows();               // 4.0.0 (2005/01/31)
    235                if( rowNo.length == 0 ) { return; }
    236
    237                // names なしの場合は、Query より取得する。  4.0.0 (2005/01/31)
    238                if( names == null ) {
    239//                      QueryForm form = new QueryForm( sql,table );
    240//                      clmNo = form.getColumnNos();
    241//                      query = form.getStatement();
    242//                      names = StringUtil.array2csv( form.getColumnNames() );
    243
    244                        Formatter format = new Formatter( table );
    245                        format.setFormat( sql );
    246                        query = format.getQueryFormatString();
    247                        clmNo = format.getClmNos();
    248                        names = StringUtil.array2csv( table.getNames() );
    249                }
    250                else {
    251                        clmNo = getTableColumnNo( StringUtil.csv2Array( names ) );
    252                        query = sql;
    253                }
    254
    255                int row;
    256                boolean okFlag ;
    257                List<Integer> list = new ArrayList<Integer>();
    258                String[] values ;
    259                for( int j=0; j<rowNo.length; j++ ) {
    260                        okFlag = true;
    261                        row = rowNo[j];
    262                        values = getTableModelData( clmNo,row );
    263                        int cnt = DBUtil.dbExist( query,values,getApplicationInfo(),dbid );
    264
    265                        String modifyType = table.getModifyType( row );
    266                        if( ( exist.equalsIgnoreCase( "true" ) ||
    267                                ( exist.equalsIgnoreCase( "auto" ) && (
    268                                                DBTableModel.UPDATE_TYPE.equals( modifyType ) ||
    269                                                DBTableModel.DELETE_TYPE.equals( modifyType ) ) ) ) && cnt <= 0 ) {
    270                                // ERR0025=データ未登録エラー。キー={0}、値={1} のデータは、存在していません。
    271                                String vals = StringUtil.array2csv( values );
    272                                errMessage.addMessage( row,ErrorMessage.NG,"ERR0025",names,vals );
    273                                okFlag = false;
    274                        }
    275                        // 4.0.0.0 (2007/11/28) 論理処理の不具合修正(カッコの付ける位置間違い)
    276                        else if( ( exist.equalsIgnoreCase( "false" ) ||
    277                                         ( exist.equalsIgnoreCase( "auto" ) &&
    278                                                        DBTableModel.INSERT_TYPE.equals( modifyType ) ) ) && cnt > 0 ) {
    279                                // ERR0026=データ登録済みエラー。キー={0}、値={1} のデータは、すでに存在しています。
    280                                String vals = StringUtil.array2csv( values );
    281                                errMessage.addMessage( row,ErrorMessage.NG,"ERR0026",names,vals );
    282                                okFlag = false;
    283                        }
    284                        else if( exist.equalsIgnoreCase( "one" ) && cnt > 1 ) {
    285                                // ERR0027=データ２重登録エラー。キー={0}、値={1} のデータは、重複して存在しています。
    286                                String vals = StringUtil.array2csv( values );
    287                                errMessage.addMessage( row,ErrorMessage.NG,"ERR0027",names,vals );
    288                                okFlag = false;
    289                        }
    290                        if( errRemove && okFlag ) { list.add( row ); }
    291                }
    292                if( errRemove ) {
    293                        Integer[] in = list.toArray( new Integer[list.size()] );
    294                        int[] newRowNo = new int[in.length];
    295                        for( int i=0; i<in.length; i++ ) {
    296                                newRowNo[i] = in[i].intValue();
    297                        }
    298                        setParameterRows( newRowNo );
    299                }
    300        }
    301
    302        /**
    303         * 【廃止】(通常は使いません)結果をDBTableModelに書き込んで、sessionに登録するときのキーを指定します。
    304         *
    305         * @og.tag
    306         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
    307         *
    308         * @param       id sessionに登録する時の ID
    309         * @deprecated クラスが廃止されました。
    310         */
    311        @Deprecated public void setTableId( final String id ) {
    312                tableId   = nval( getRequestParameter( id ),tableId );  // 3.8.0.9 (2005/10/17)
    313        }
    314
    315        /**
    316         * 【廃止】(通常は使いません)Queryオブジェクトを作成する時のDB接続IDを指定します。
    317         *
    318         * @og.tag Queryオブジェクトを作成する時のDB接続IDを指定します。
    319         *
    320         * @param       id データベース接続ID
    321         * @deprecated クラスが廃止されました。
    322         */
    323        @Deprecated public void setDbid( final String id ) {
    324                dbid = nval( getRequestParameter( id ),dbid );
    325        }
    326
    327        /**
    328         * 【廃止】コマンド(ENTRY)をセットします。
    329         *
    330         * @og.tag
    331         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
    332         * フィールド定数値のいづれかを、指定できます。
    333         *
    334         * @param       cmd コマンド(public static final 宣言されている文字列)
    335         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.TableExistTag.CMD_NEW">コマンド定数</a>
    336         * @deprecated クラスが廃止されました。
    337         */
    338        @Deprecated public void setCommand( final String cmd ) {
    339                String cmd2 = getRequestParameter( cmd );
    340                if( cmd2 != null && cmd2.length() > 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
    341        }
    342
    343        /**
    344         * 【廃止】引数にセットすべき データの名称(カラム名)をCSV形式で複数指定します。
    345         *
    346         * @og.tag
    347         * 複数ある場合は、カンマ区切り文字で渡します。
    348         * 引数をnames ではなく、[カラム名]形式で直接指定するほうが、SQL文が判りやすくなります。
    349         *
    350         * @param       nm 引数の名称(複数ある場合は、カンマ区切り文字)
    351         * @deprecated クラスが廃止されました。
    352         */
    353        @Deprecated public void setNames( final String nm ) {
    354                names = nval( getRequestParameter( nm ),names );
    355        }
    356
    357        /**
    358         * 【廃止】チェックするデータベース名(from 句)を指定します。
    359         *
    360         * @og.tag
    361         * from 句 に指定するデータベース名です。
    362         *
    363         * @param       fm データベースID
    364         * @deprecated クラスが廃止されました。
    365         */
    366        @Deprecated public void setFrom( final String fm ) {
    367                from = nval( getRequestParameter( fm ),from );
    368        }
    369
    370        /**
    371         * 【廃止】チェックする検索条件(where句)を指定します。
    372         *
    373         * @og.tag
    374         * where 区 に指定する検索条件です。? の部分に、names 属性で指定した
    375         * カラムのデータが、DBTableModelより取り出されて適用されます。
    376         * または、[カラム名]形式で、直接指定することもできます。その場合は、
    377         * name 属性は指定する必要がありません。
    378         * [カラム名]の前後に、(')シングルコーテーションは、不要です。
    379         *
    380         * @param       wr 検索条件(where句)
    381         * @deprecated クラスが廃止されました。
    382         */
    383        @Deprecated public void setWhere( final String wr ) {
    384                where = nval( getRequestParameter( wr ),where );
    385        }
    386
    387        /**
    388         * 【廃止】データベースのチェック方法(auto/true/false/one/notuse)を指定します(初期値:｢auto:自動｣)。
    389         *
    390         * @og.tag
    391         * exist 属性に指定された 、｢true:存在する｣、｢false:存在しない｣、｢one:ひとつ以下｣、
    392         * の値は、いずれの場合も、成立時は、正常とみなします。
    393         * ｢auto:自動｣は、DBTableModeleのmodifyType(A,C,D)に応じて、チェックします。
    394         * A,C,D は、entryタグにコマンドを渡してデータを作成したときに、内部で作成されます。
    395         * notuse は、チェックを行いません。これは、このタグを共有使用する場合に、外部で
    396         * チェックを行うかどうかを指定できるようにするために使用します。
    397         * (｢true:存在する｣ には、データが存在した場合に、ＯＫで、なければエラーです。)
    398         * 初期値は、｢auto:自動｣です。
    399         *
    400         * @param       ext チェック方法(｢auto:自動｣、｢true:存在する｣、｢false:存在しない｣、｢one:ひとつ以下｣、｢notuse:チェックしない｣)
    401         * @deprecated クラスが廃止されました。
    402         */
    403        @Deprecated public void setExist( final String ext ) {
    404                exist = nval( getRequestParameter( ext ),exist );
    405                if( !"auto".equalsIgnoreCase( exist ) &&
    406                        !"true".equalsIgnoreCase( exist ) &&
    407                        !"false".equalsIgnoreCase( exist ) &&
    408                        !"one".equalsIgnoreCase( exist ) &&
    409                        !"notuse".equalsIgnoreCase( exist ) ) {
    410                                String errMsg = "exist 属性は、(auto,true,false,one,notuse)を指定してください。 [" + exist + "]" + HybsSystem.CR ;
    411                                throw new HybsSystemException( errMsg );
    412                }
    413        }
    414
    415        /**
    416         * 【廃止】エラー時の選択行を取り除いて継続処理を行うかどうか[true/false]を指定します(初期値:false)。
    417         *
    418         * @og.tag
    419         * exist 属性に指定された 、｢true:存在する｣、｢false:存在しない｣、｢one:ひとつ以下｣、
    420         * に対して、エラーが発生した選択行番号を、取り除いて以下の処理を継続するかどうかを
    421         * 指定します。
    422         * true に設定した場合は、エラーデータを削除し、継続処理を行うことができます。
    423         * flase の場合は、エラーデータを表示して、継続処理を停止します。
    424         * 初期値は、｢false:エラー時停止｣です。
    425         *
    426         * @param       flag エラー時の継続処理 [true:エラー行番号を取り除き継続処理/false:エラー時停止]
    427         * @deprecated クラスが廃止されました。
    428         */
    429        @Deprecated public void setErrRemove( final String flag ) {
    430                errRemove = nval( getRequestParameter( flag ),errRemove );
    431        }
    432
    433        /**
    434         *  カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
    435         *
    436         * @param       nameArray カラム名配列
    437         *
    438         * @return      カラムNo配列
    439         */
    440        private int[] getTableColumnNo( final String[] nameArray ) {
    441                int[] clmNo = new int[ nameArray.length ];
    442                for( int i=0; i<clmNo.length; i++ ) {
    443                        clmNo[i] = table.getColumnNo( nameArray[i] );
    444                }
    445                return clmNo;
    446        }
    447
    448        /**
    449         *  指定の行番号の、カラムNo配列(int[])に対応した値の配列を返します。
    450         *
    451         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を
    452         * 処理の対象とします。
    453         *
    454         * @param       clmNo   カラムNo配列
    455         * @param       row             行番号
    456         *
    457         * @return      行番号とカラムNo配列に対応した、値の配列
    458         */
    459        private String[] getTableModelData( final int[] clmNo,final int row ) {
    460                String[] values = new String[ clmNo.length ];
    461                for( int i=0; i<values.length; i++ ) {
    462                        values[i] = table.getValue( row,clmNo[i] ) ;
    463                }
    464                return values;
    465        }
    466
    467        /**
    468         * シリアライズ用のカスタムシリアライズ書き込みメソッド
    469         *
    470         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
    471         * @serialData 一部のオブジェクトは、シリアライズされません。
    472         *
    473         * @param       strm    ObjectOutputStreamオブジェクト
    474         * @throws IOException  入出力エラーが発生した場合
    475         */
    476        private void writeObject( final ObjectOutputStream strm ) throws IOException {
    477                strm.defaultWriteObject();
    478        }
    479
    480        /**
    481         * シリアライズ用のカスタムシリアライズ読み込みメソッド
    482         *
    483         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
    484         *
    485         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
    486         * @serialData 一部のオブジェクトは、シリアライズされません。
    487         *
    488         * @param       strm    ObjectInputStreamオブジェクト
    489         * @see #release2()
    490         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
    491         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
    492         */
    493        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
    494                strm.defaultReadObject();
    495        }
    496
    497        /**
    498         * このオブジェクトの文字列表現を返します。
    499         * 基本的にデバッグ目的に使用します。
    500         *
    501         * @return このクラスの文字列表現
    502         */
    503        @Override
    504        public String toString() {
    505                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
    506                                .println( "VERSION"             ,VERSION        )
    507                                .println( "tableId"             ,tableId        )
    508                                .println( "dbid"                ,dbid           )
    509                                .println( "command"             ,command        )
    510                                .println( "sql"                 ,sql            )
    511                                .println( "names"               ,names          )
    512                                .println( "from"                ,from           )
    513                                .println( "where"               ,where          )
    514                                .println( "exist"               ,exist          )
    515                                .println( "CMD_ENTRY"   ,CMD_ENTRY      )
    516                                .println( "Other..."    ,getAttributes().getAttribute() )
    517                                .fixForm().toString() ;
    518        }
    519}