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