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     */
016    package org.opengion.fukurou.process;
017    
018    import org.opengion.fukurou.util.Argument;
019    import org.opengion.fukurou.util.SystemParameter;
020    import org.opengion.fukurou.util.LogWriter;
021    
022    import org.opengion.fukurou.util.HybsEntry ;
023    import org.opengion.fukurou.util.Closer;
024    import org.opengion.fukurou.util.StringUtil;            // 5.7.2.3 (2014/01/31)
025    import org.opengion.fukurou.db.ConnectionFactory;
026    
027    import java.util.Map ;
028    import java.util.LinkedHashMap ;
029    import java.util.Locale ;
030    
031    import java.sql.Connection;
032    import java.sql.Statement;
033    import java.sql.ResultSet;
034    import java.sql.ResultSetMetaData;
035    import java.sql.SQLException;
036    
037    /**
038     * Process_DBReaderは、データベ?スから読み取った?容を?LineModel に設定後?
039     * 下流に渡す?FirstProcess インターフェースの実?ラスです?
040     *
041     * ??タベ?スから読み取った?容より、LineModelを作?し?下?プロセス
042     * チェインは、チェインして?ため、データは上流から下流へと渡されます?)
043     * に渡します?ここで?できるのは、検索系SQL のみです?
044     *
045     * ??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に
046     * 設定された接?Connection)を使用します?
047     *
048     * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ??
049     * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に
050     * 繋げてください?
051     *
052     * SQL?は、{@DATE.YMDH}等?シス?変数が使用できます?
053     *
054     * @og.formSample
055     *  Process_DBReader -dbid=DBGE -sql="select * from GEA08"
056     *
057     *   [ -dbid=DB接続ID       ] ??dbid=DBGE (? Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規?
058     *   [ -sql=検索SQL?      ] ??sql="select * from GEA08"
059     *   [ -sqlFile=検索SQL?ァ???] ??sqlFile=select.sql
060     *                                 -sql= を指定しな??合?、ファイルで??してください?
061     *   [ -sql_XXXX=固定?     ] ??sql_SYSTEM_ID=GE
062     *                                SQL?の{@XXXX}??を指定?固定?で置き換えます?
063     *                                WHERE SYSTEM_ID='{@SYSTEM_ID}' ?WHERE SYSTEM_ID='GE'
064     *   [ -asClms=置換カ?ム名    ] ??asClms="FGJ:CDJ SEQ123:UNIQ" ??ム名:新??ム名 の??゚ー?区?
065     *   [ -fetchSize=100       ] ?フェ?する行数(初期値:100)
066     *   [ -display=false|true  ] ?結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
067     *   [ -debug=false|true    ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
068     *
069     * @version  4.0
070     * @author   Kazuhiko Hasegawa
071     * @since    JDK5.0,
072     */
073    public class Process_DBReader extends AbstractProcess implements FirstProcess {
074            private static final String SQL_KEY  = "sql_" ;
075    
076            private Connection      connection      = null;
077            private Statement       stmt            = null ;
078            private ResultSet       resultSet       = null;
079            private LineModel       newData         = null;
080            private int                     count           = 0;
081            private int                     fetchSize       = 100;
082    
083            private String          dbid            = null;
084            private boolean         display         = false;        // 表示しな?
085            private boolean         debug           = false;        // 5.7.3.0 (2014/02/07) ????
086    
087            private static final Map<String,String> mustProparty   ;          // ?プロパティ???チェ?用 Map
088            private static final Map<String,String> usableProparty ;          // ?プロパティ?整合?チェ? Map
089    
090            static {
091                    mustProparty = new LinkedHashMap<String,String>();
092    
093                    usableProparty = new LinkedHashMap<String,String>();
094                    usableProparty.put( "dbid",     "Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規? );
095                    usableProparty.put( "sql",              "検索SQL?sql or sqlFile ??)? \"select * from GEA08\"" );
096                    usableProparty.put( "sqlFile",  "検索SQLファイル(sql or sqlFile ??)? select.sql" );
097                    usableProparty.put( "sql_",             "SQL?の{&#064;XXXX}??を指定?固定?で置き換えます?" +
098                                                                            CR + "WHERE SYSTEM_ID='{&#064;SYSTEM_ID}' ?WHERE SYSTEM_ID='GE'" );
099                    // 5.7.2.3 (2014/01/31) asClms 追?
100                    usableProparty.put( "asClms",   "??ム名:新??ム名 の??゚ー?区?で??ム名の置換を行う" );
101                    usableProparty.put( "fetchSize","フェ?する行数 (初期値:100)" );
102                    usableProparty.put( "display",  "結果を標準?力に表示する(true)かしな?false)? +
103                                                                                    CR + "(初期値:false:表示しな?" );
104                    usableProparty.put( "debug",    "????を標準?力に表示する(true)かしな?false)? +
105                                                                                    CR + "(初期値:false:表示しな?" );                // 5.7.3.0 (2014/02/07) ????
106            }
107    
108            /**
109             * ?ォルトコンストラクター?
110             * こ?クラスは、動??されます??ォルトコンストラクターで?
111             * super クラスに対して、?な初期化を行っておきます?
112             *
113             */
114            public Process_DBReader() {
115                    super( "org.opengion.fukurou.process.Process_DBReader",mustProparty,usableProparty );
116            }
117    
118            /**
119             * プロセスの初期化を行います?初めに??、呼び出されます?
120             * 初期処?ファイルオープン??オープン?に使用します?
121             *
122             * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
123             * @og.rev 5.7.2.3 (2014/01/31) asClms 追?
124             *
125             * @param   paramProcess ??タベ?スの接続???などを持って?オブジェク?
126             */
127            public void init( final ParamProcess paramProcess ) {
128                    Argument arg = getArgument();
129    
130                    String sql              = arg.getFileProparty("sql","sqlFile",true);
131    
132                    // 5.7.2.3 (2014/01/31) asClms 追?
133                    String asClms   = arg.getProparty("asClms");
134    
135                    String fSize    = arg.getProparty("fetchSize");
136                    display                 = arg.getProparty("display",display);
137                    debug                   = arg.getProparty("debug",debug);                               // 5.7.3.0 (2014/02/07) ????
138    //              if( debug ) { println( arg.toString() ); }                      // 5.7.3.0 (2014/02/07) ????
139    
140                    dbid                    = arg.getProparty("dbid");
141                    connection              = paramProcess.getConnection( dbid );
142    
143                    // 3.8.0.1 (2005/06/17) SQL?? {@XXXX} ??の固定?への置き換?
144                    HybsEntry[] entry       =arg.getEntrys(SQL_KEY);                //配?
145                    SystemParameter sysParam = new SystemParameter( sql );
146                    sql = sysParam.replace( entry );
147    
148                    // SQL?? {@XXXX} ??の固定?への置き換?
149                    if( fSize != null ) { fetchSize = Integer.parseInt( fSize ); }
150    
151                    try {
152                            stmt = connection.createStatement();
153                            if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); }
154                            resultSet = stmt.executeQuery( sql );
155    
156                            // 5.7.2.3 (2014/01/31) asClms 処?追??
157    //                      newData = createLineModel( resultSet );
158                            newData = createLineModel( resultSet,asClms );
159    
160                            if( display ) { println( newData.nameLine() ); }
161                    }
162                    catch (SQLException ex) {
163                            // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
164                            String errMsg = "Query の実行に問題があります?" + CR
165                                            + "errMsg=[" + ex.getMessage() + "]" + CR
166                                            + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
167                                            + "dbid=[" + dbid + "]" + CR
168                                            + "sql =[" + sql + "]" ;
169    //                      String errMsg = "Query の実行に問題があります?[" + sql + "]" ;
170                            throw new RuntimeException( errMsg,ex );
171                    }
172            }
173    
174            /**
175             * プロセスの終?行います??に??、呼び出されます?
176             * 終???ファイルクローズ??クローズ?に使用します?
177             *
178             * @og.rev 4.0.0.0 (2007/11/27) commit,rollback,remove 処?追?
179             *
180             * @param   isOK ト?タルで、OK?たかど?[true:成功/false:失敗]
181             */
182            public void end( final boolean isOK ) {
183                    boolean flag1 = Closer.resultClose( resultSet );
184                    resultSet  = null;
185                    boolean flag2 = Closer.stmtClose( stmt );
186                    stmt       = null;
187    
188                    ConnectionFactory.remove( connection,dbid );
189    
190                    if( !flag1 || !flag2 ) {
191                            String errMsg = "ス??トメントをクローズ出来ません?;
192                            throw new RuntimeException( errMsg );
193                    }
194            }
195    
196            /**
197             * こ???タの処?おいて、次の処?出来るかど?を問?わせます?
198             * こ?呼び出し1回毎に、次の??タを取得する準備を行います?
199             *
200             * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
201             *
202             * @return      処?きる:true / 処?きな?false
203             */
204            public boolean next() {
205                    try {
206                            return resultSet.next() ;
207                    }
208                    catch (SQLException ex) {
209                            String errMsg = "ネクストすることが?来ません?
210                                            + "errMsg=[" + ex.getMessage() + "]" + CR
211                                            + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR ;
212    //                      String errMsg = "ネクストすることが?来ません?;
213                            throw new RuntimeException( errMsg,ex );
214                    }
215            }
216    
217            /**
218             * ??に?行データである LineModel を作?しま?
219             * FirstProcess は、次?処?チェインして???の行データ?
220             * 作?して、後続? ChainProcess クラスに処?ータを渡します?
221             *
222             * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
223             *
224             * @param       rowNo   処?の行番号
225             *
226             * @return      処?換後?LineModel
227             */
228            public LineModel makeLineModel( final int rowNo ) {
229                    count++ ;
230                    try {
231                            for(int clm = 0; clm < newData.size(); clm++) {
232                                    Object obj = resultSet.getObject(clm+1);
233                                    if( obj == null ) {
234                    //                      newData.setValue( clm, "" );
235                                            newData.setValue( clm, null );
236                                    }
237                                    else {
238                                            newData.setValue( clm, obj );
239                                    }
240                            }
241                            newData.setRowNo( rowNo );
242                            if( display ) { println( newData.dataLine() ); }
243                    }
244                    catch (SQLException ex) {
245                            // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
246                            String errMsg = "??タを??きませんでした?" + rowNo + "]件目 " + CR
247                                            + "errMsg=[" + ex.getMessage() + "]" + CR
248                                            + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
249                                            + "dbid=[" + dbid + "]" + CR
250                                            + "data=[" + newData.dataLine() + "]" + CR ;
251    //                      String errMsg = "??タを??きませんでした?" + rowNo + "]件目 "
252    //                                                              + newData.toString() ;
253                            throw new RuntimeException( errMsg,ex );
254                    }
255                    return newData;
256            }
257    
258            /**
259             * ?で使用する LineModel を作?します?
260             * こ?クラスは、?ロセスチェインの基点となります?で、新?LineModel を返します?
261             * Exception 以外では、? LineModel オブジェクトを返します?
262             * 第?引数は、カラ?の置き換え指示です?null の場合?、何もしません?
263             * 通常は、SELECT CLM1 AS CLM2 FROM *** とする?を?CLM1:CLM2 と?する事で
264             * SELECT CLM1 FROM *** のまま、以降?処? CLM2 で扱えます?
265             *
266             * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
267             * @og.rev 5.7.2.3 (2014/01/31) asClms 追?
268             *
269             * @param       rs      ??タベ?スカーソル(リザルトセ?)
270             * @param       asClms  ??ム名:新??ム名 の??゚ー?区???
271             *
272             * @return      ??タベ?スから取り出して変換した LineModel
273             * @throws RuntimeException カラ?を取得できなかった?合?
274             */
275    //      private LineModel createLineModel( final ResultSet rs ) {
276            private LineModel createLineModel( final ResultSet rs , final String asClms ) {
277                    LineModel model = new LineModel();
278    
279                    try {
280                            ResultSetMetaData metaData      = rs.getMetaData();
281    
282                            int size =  metaData.getColumnCount();
283                            model.init( size );
284    
285                            for(int clm = 0; clm < size; clm++) {
286                                    String name = (metaData.getColumnLabel(clm+1)).toUpperCase(Locale.JAPAN) ;
287                                    // 5.7.2.3 (2014/01/31) asClms 追?
288                                    if( asClms != null ) {
289                                            // asClms の null判定も、toUpperCase 処?行って?が?判りにくいので?
290                                            name = StringUtil.caseReplace( name,asClms,false );
291                                    }
292                                    model.setName( clm,name );
293                            }
294                    }
295                    catch (SQLException ex) {
296                            // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
297                            String errMsg = "ResultSetMetaData から、カラ?を取得できませんでした? + CR
298                                            + "errMsg=[" + ex.getMessage() + "]" + CR
299                                            + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
300                                            + "dbid=[" + dbid + "]" + CR ;
301    //                      String errMsg = "ResultSetMetaData から、カラ?を取得できませんでした?;
302                            throw new RuntimeException( errMsg,ex );
303                    }
304                    return model;
305            }
306    
307            /**
308             * プロセスの処?果のレポ?ト表現を返します?
309             * 処??ログラ?、?力件数、?力件数などの??です?
310             * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
311             * 形式で出してください?
312             *
313             * @return   処?果のレポ??
314             */
315            public String report() {
316                    String report = "[" + getClass().getName() + "]" + CR
317                                    + TAB + "DBID        : " + dbid + CR
318                                    + TAB + "Input Count : " + count ;
319    
320                    return report ;
321            }
322    
323            /**
324             * こ?クラスの使用方法を返します?
325             *
326             * @return      こ?クラスの使用方?
327             */
328            public String usage() {
329                    StringBuilder buf = new StringBuilder();
330    
331                    buf.append( "Process_DBReaderは、データベ?スから読み取った?容を?LineModel に設定後?"       ).append( CR );
332                    buf.append( "下流に渡す?FirstProcess インターフェースの実?ラスです?"                                    ).append( CR );
333                    buf.append( CR );
334                    buf.append( "??タベ?スから読み取った?容より、LineModelを作?し?下?プロセス"                 ).append( CR );
335                    buf.append( "チェインは、チェインして?ため、データは上流から下流へと渡されます?)"             ).append( CR );
336                    buf.append( "に渡します?ここで?できるのは、検索系SQL のみです?"                                          ).append( CR );
337                    buf.append( CR );
338                    buf.append( "??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に"                    ).append( CR );
339                    buf.append( "設定された接?Connection)を使用します?"                                                                               ).append( CR );
340                    buf.append( CR );
341                    buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
342                    buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に"             ).append( CR );
343                    buf.append( "繋げてください?                                                                                                                              ).append( CR );
344                    buf.append( CR );
345                    buf.append( "SQL?は、{@DATE.YMDH}等?シス?変数が使用できます?"                                          ).append( CR );
346                    buf.append( CR ).append( CR );
347    
348                    buf.append( getArgument().usage() ).append( CR );
349    
350                    return buf.toString();
351            }
352    
353            /**
354             * こ?クラスは、main メソ?から実行できません?
355             *
356             * @param       args    コマンド引数配?
357             */
358            public static void main( final String[] args ) {
359                    LogWriter.log( new Process_DBReader().usage() );
360            }
361    }