    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.plugin.table;
    017
    018import java.io.File;
    019import java.io.PrintWriter;
    020
    021import org.opengion.fukurou.system.OgBuilder ;                          // 6.4.4.1 (2016/03/18)
    022import org.opengion.fukurou.util.ErrorMessage;
    023import org.opengion.fukurou.util.FileUtil;
    024import org.opengion.fukurou.util.FixLengthData;
    025import org.opengion.fukurou.util.StringUtil;
    026import org.opengion.hayabusa.common.HybsSystem;
    027import org.opengion.hayabusa.common.HybsSystemException;
    028import org.opengion.hayabusa.db.AbstractTableFilter;
    029import org.opengion.hayabusa.db.DBTableModel;
    030
    031/**
    032 * TableFilter_SEQUENCE は、TableUpda インターフェースを継承した、DBTableModel 処理用の
    033 * 実装クラスです。
    034 *
    035 * ここでは、シーケンス一覧の検索結果より、GF09 のシーケンス定義テーブルから
    036 * 必要な情報を取得し、シーケンス作成スクリプトを作成します。
    037 *
    038 * この処理を実行するには、DBTableModelのカラムとして、
    039 *  SYSTEM_ID,TBLSYU,SEQNAME,INCREBY,STARTVAL,MINVAL,MAXVAL,FGCYCLE,SUCACHE
    040 * が必要です。
    041 *
    042 * パラメータは、tableFilterタグの keys, vals にそれぞれ記述するか、BODY 部にCSS形式で記述します。
    043 * 【パラメータ】
    044 *  {
    045 *       DIR : {&#064;BASE_DIR}/sql/install/03_SEQ ;    出力ファイルの基準フォルダ(必須)
    046 *       XML : false ;                                  XML出力を行うかどうか[true/false]を指定します(初期値:false)。
    047 *  }
    048 *
    049 * @og.formSample
    050 * ●形式：
    051 *      select SYSTEM_ID,TBLSYU,SEQNAME,INCREBY,STARTVAL,MINVAL,MAXVAL,FGCYCLE,SUCACHE from GF09
    052 *
    053 *      ① &lt;og:tableFilter classId="SEQUENCE" keys="DIR,XML" vals='"{&#064;BASE_DIR}/sql/install/03_SEQ,"' /&gt;
    054 *
    055 *      ② &lt;og:tableFilter classId="SEQUENCE" &gt;
    056 *               {
    057 *                   DIR : {&#064;BASE_DIR}/sql/install/03_SEQ ;
    058 *                   XML : false ;
    059 *               }
    060 *         &lt;/og:tableFilter&gt;
    061 *
    062 * @og.rev 5.1.9.0 (2010/08/01) DB定義DB・シーケンス定義追加
    063 * @og.rev 5.6.6.0 (2013/07/05) keys の整合性チェックを追加
    064 *
    065 * @version  0.9.0  2010/08/01
    066 * @author   Hiroki Nakamura
    067 * @since    JDK1.1,
    068 */
    069public class TableFilter_SEQUENCE extends AbstractTableFilter {
    070        /** このプログラムのVERSION文字列を設定します。   {@value} */
    071        private static final String VERSION = "6.5.0.1 (2016/10/21)" ;
    072
    073        private static final String[] DBKEY = {"SYSTEM_ID","TBLSYU","SEQNAME","INCREBY","STARTVAL","MINVAL","MAXVAL","FGCYCLE","SUCACHE" };
    074
    075        /** データのアクセス用の配列番号 {@value} */
    076        protected static final int SYSTEM_ID            = 0;
    077        /** データのアクセス用の配列番号 {@value} */
    078        protected static final int TBLSYU                       = 1;
    079        /** データのアクセス用の配列番号 {@value} */
    080        protected static final int SEQNAME                      = 2;
    081        /** データのアクセス用の配列番号 {@value} */
    082        protected static final int INCREBY                      = 3;
    083        /** データのアクセス用の配列番号 {@value} */
    084        protected static final int STARTVAL                     = 4;
    085        /** データのアクセス用の配列番号 {@value} */
    086        protected static final int MINVAL                       = 5;
    087        /** データのアクセス用の配列番号 {@value} */
    088        protected static final int MAXVAL                       = 6;
    089        /** データのアクセス用の配列番号 {@value} */
    090        protected static final int FGCYCLE                      = 7;
    091        /** データのアクセス用の配列番号 {@value} */
    092        protected static final int SUCACHE                      = 8;
    093
    094        private static final String ENCODE = "UTF-8" ; // 4.3.6.6 (2009/05/15)
    095
    096        private static final String CMNT  = "************************************************************************" ;
    097
    098        private static final int X = FixLengthData.X ;
    099        private static final int K = FixLengthData.K ;
    100
    101        /** 各種定数 */
    102        // 6.0.2.3 (2014/10/10) AbstractTableFilter へ移動
    103
    104        /** XML形式かどうか  */
    105
    106        /**
    107         * デフォルトコンストラクター
    108         *
    109         * @og.rev 6.4.1.1 (2016/01/16) keysMap を、サブクラスから設定させるように変更。
    110         */
    111        public TableFilter_SEQUENCE() {
    112                super();
    113                initSet( "DIR"  , "出力ファイルの基準フォルダ(必須)"                                           );
    114                initSet( "XML"  , "XML出力を行うかどうか[true/false]を指定(初期値:false)"      );
    115        }
    116
    117        /**
    118         * DBTableModel処理を実行します。
    119         *
    120         * @og.rev 5.5.2.6 (2012/05/25) protected変数を、private化したため、getterメソッドで取得するように変更
    121         * @og.rev 6.0.2.3 (2014/10/10) EXEC_END_TAG 自体にCRを追加。キャッシュします。
    122         * @og.rev 6.3.7.0 (2015/09/04) AutoCloseableを使用したtry-with-resources構築に対応。
    123         * @og.rev 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。
    124         *
    125         * @return      実行結果のテーブルモデル
    126         */
    127        public DBTableModel execute() {
    128                isXml = StringUtil.nval( getValue( "XML" ), false );
    129                execEndTag = isXml ? CR + EXEC_END_TAG : ";" ;  // 6.0.2.3 (2014/10/10)
    130
    131                final File dir = new File( getValue( "DIR" ) );
    132                if( ! dir.exists() && ! dir.mkdirs() ) {
    133                        final String errMsg = "所定のフォルダが作成できませんでした。[" + dir + "]" ;
    134                        // 4.3.4.4 (2009/01/01)
    135                        throw new HybsSystemException( errMsg );
    136                }
    137
    138                // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD)
    139                final int[] clmNo = getTableColumnNo( DBKEY );
    140                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
    141                final DBTableModel table = getDBTableModel();           // 5.5.2.6 (2012/05/25) インターフェースにgetterメソッド追加
    142                final int rowCnt  = table.getRowCount();
    143                for( int row=0; row<rowCnt; row++ ) {
    144                        final String[] data = table.getValues( row );                   // 6.3.9.1 (2015/11/27)
    145                        final String seqName = data[clmNo[SEQNAME]];
    146                        // 6.3.7.0 (2015/09/04) AutoCloseableを使用したtry-with-resources構築に対応。
    147                        try( PrintWriter writer = FileUtil.getPrintWriter( new File( dir,seqName + ( isXml ? ".xml" : ".sql" ) ),ENCODE ) ) {
    148                                if( isXml ) { writer.println( XML_START_TAG ); }
    149                                writer.print( makeHeadLine( clmNo,data ) );
    150                                writer.println( makeLineList( clmNo,data ) );
    151                                if( isXml ) { writer.println( XML_END_TAG ); }
    152                        }
    153                        catch( final RuntimeException ex ) {            // catch は、close() されてから呼ばれます。
    154                                // 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。
    155                                final ErrorMessage errMessage = makeErrorMessage( "TableFilter_SEQNENCE Error",ErrorMessage.NG )
    156                                        .addMessage( row+1,ErrorMessage.NG,"SEQUENCE"
    157                                                , "SEQ=[" + seqName + "]"
    158                                                , StringUtil.array2csv( data )
    159                                        )
    160                                        .addMessage( ex );
    161                                // BAT から呼び出す場合があるため、標準エラー出力にも情報を出しておきます。
    162                                System.out.println( errMessage );
    163                        }
    164                }
    165
    166                return table;
    167        }
    168
    169        /**
    170         * ヘッダー部分の処理を実行します。
    171         *
    172         * @og.rev 5.6.6.0 (2013/07/05) FixLengthData の簡易コンストラクタを使用
    173         *
    174         * @param       clmNo   カラム番号配列
    175         * @param       data    １行分のデータ配列
    176         *
    177         * @return      ヘッダー部分の文字列
    178         * @og.rtnNotNull
    179         */
    180        protected String makeHeadLine( final int[] clmNo,final String[] data ) {
    181                final String seqName = data[clmNo[SEQNAME]];
    182                final String LINE1 = seqName;
    183                final String LINE2 = "Created : " + HybsSystem.getDate() ;
    184
    185                // 5.6.6.0 (2013/07/05) FixLengthData の簡易コンストラクタを使用
    186                final int[] addLen = new int[] { 0,0,0 };       // 各データ間のスペース
    187                final int[] type   = new int[] { X,K,X };       // 各データの種別 X:半角 S:空白前埋め K:全角混在
    188                final FixLengthData fixData = new FixLengthData( addLen,type );
    189
    190                final String[][] outData = new String[][] {
    191                        { "/**",        CMNT ,  "**/" },
    192                        { "/* ",        LINE1,  " */" },
    193                        { "/* ",        LINE2,  " */" },
    194                        { "/**",        CMNT ,  "**/" },
    195                };
    196
    197                fixData.addAllListData( outData );
    198
    199                return fixData.getAllFixData();
    200        }
    201
    202        /**
    203         * シーケンス作成の処理を実行します。
    204         *
    205         * @og.rev 6.0.2.3 (2014/10/10) isXml で、CR + EXEC_END_TAG のキャッシュ(execEndTag)を利用します。
    206         * @og.rev 6.4.4.1 (2016/03/18) StringBuilderの代わりに、OgBuilderを使用する。
    207         *
    208         * @param       clmNo   カラム番号配列
    209         * @param       data    １行分のデータ配列
    210         *
    211         * @return      シーケンス作成
    212         * @og.rtnNotNull
    213         */
    214        protected String makeLineList( final int[] clmNo,final String[] data ) {
    215                final String execSeqSQL = "SELECT COUNT(*) FROM USER_SEQUENCES WHERE SEQUENCE_NAME=UPPER('" ;
    216
    217                return new OgBuilder()
    218//                              .appendIfCR( isXml , EXEC_START_TAG )
    219                                .appendIfCR( isXml , EXEC_EXISTS_0_TAG )                //  EXISTS_0 判定は、XML の場合のみ。
    220                                .appendIfCR( isXml , execSeqSQL , data[clmNo[SEQNAME]] , "');" )
    221                                .appendCR( "CREATE SEQUENCE "   , data[clmNo[SEQNAME]] )
    222                                .append( "  START WITH "                , data[clmNo[STARTVAL]] )
    223                                .append( " INCREMENT BY "               , data[clmNo[INCREBY]] )
    224                                .append( " MINVALUE "                   , data[clmNo[MINVAL]] )
    225                                .append( " MAXVALUE "                   , data[clmNo[MAXVAL]] )
    226                                .appendCase( "1".equals( data[clmNo[FGCYCLE]] )                 // flagで選択されます。
    227                                                                , " CYCLE" , " NOCYCLE" )                               // true , false
    228                                .appendCase( Integer.parseInt( data[clmNo[SUCACHE]] ) <= 0      // 注意：判定条件を反転してます。
    229                                                                , " NOCACHE"                                                    // true
    230                                                                , " CACHE " , data[clmNo[SUCACHE]] )    // false
    231                                .append( execEndTag )
    232                                .toString();
    233        }
    234}