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             * @param   paramProcess ??タベ?スの接続???などを持って?オブジェク?
115             */
116            public void init( final ParamProcess paramProcess ) {
117                    Argument arg = getArgument();
118    
119                    String sql              =arg.getFileProparty("sql","sqlFile",true);
120                    String fSize    =arg.getProparty("fetchSize");
121                    display                 =arg.getProparty("display",display);
122    
123                    dbid                    = arg.getProparty("dbid");
124                    connection              = paramProcess.getConnection( dbid );
125    
126                    // 3.8.0.1 (2005/06/17) SQL?? {@XXXX} ??の固定?への置き換?
127                    HybsEntry[] entry       =arg.getEntrys(SQL_KEY);                //配?
128                    SystemParameter sysParam = new SystemParameter( sql );
129                    sql = sysParam.replace( entry );
130    
131                    // SQL?? {@XXXX} ??の固定?への置き換?
132                    if( fSize != null ) { fetchSize = Integer.parseInt( fSize ); }
133    
134                    try {
135                            stmt = connection.createStatement();
136                            if( fetchSize > 0 ) { stmt.setFetchSize( fetchSize ); }
137                            resultSet = stmt.executeQuery( sql );
138    
139                            newData = createLineModel( resultSet );
140    
141                            if( display ) { println( newData.nameLine() ); }
142                    }
143                    catch (SQLException ex) {
144                            String errMsg = "Query の実行に問題があります?[" + sql + "]" ;
145                            throw new RuntimeException( errMsg,ex );
146                    }
147            }
148    
149            /**
150             * プロセスの終?行います??に??、呼び出されます?
151             * 終???ファイルクローズ??クローズ?に使用します?
152             *
153             * @og.rev 4.0.0.0 (2007/11/27) commit,rollback,remove 処?追?
154             *
155             * @param   isOK ト?タルで、OK?たかど?[true:成功/false:失敗]
156             */
157            public void end( final boolean isOK ) {
158                    boolean flag1 = Closer.resultClose( resultSet );
159                    resultSet  = null;
160                    boolean flag2 = Closer.stmtClose( stmt );
161                    stmt       = null;
162    
163                    ConnectionFactory.remove( connection,dbid );
164    
165                    if( !flag1 || !flag2 ) {
166                            String errMsg = "ス??トメントをクローズ出来ません?;
167                            throw new RuntimeException( errMsg );
168                    }
169            }
170    
171            /**
172             * こ???タの処?おいて、次の処?出来るかど?を問?わせます?
173             * こ?呼び出し1回毎に、次の??タを取得する準備を行います?
174             *
175             * @return      処?きる:true / 処?きな?false
176             */
177            public boolean next() {
178                    try {
179                            return resultSet.next() ;
180                    }
181                    catch (SQLException ex) {
182                            String errMsg = "ネクストすることが?来ません?;
183                            throw new RuntimeException( errMsg,ex );
184                    }
185            }
186    
187            /**
188             * ??に?行データである LineModel を作?しま?
189             * FirstProcess は、次?処?チェインして???の行データ?
190             * 作?して、後続? ChainProcess クラスに処?ータを渡します?
191             *
192             * @param       rowNo   処?の行番号
193             *
194             * @return      処?換後?LineModel
195             */
196            public LineModel makeLineModel( final int rowNo ) {
197                    count++ ;
198                    try {
199                            for(int clm = 0; clm < newData.size(); clm++) {
200                                    Object obj = resultSet.getObject(clm+1);
201                                    if( obj == null ) {
202                    //                      newData.setValue( clm, "" );
203                                            newData.setValue( clm, null );
204                                    }
205                                    else {
206                                            newData.setValue( clm, obj );
207                                    }
208                            }
209                            newData.setRowNo( rowNo );
210                            if( display ) { println( newData.dataLine() ); }
211                    }
212                    catch (SQLException ex) {
213                            String errMsg = "??タを??きませんでした?" + rowNo + "]件目 "
214                                                                    + newData.toString() ;
215                            throw new RuntimeException( errMsg,ex );
216                    }
217                    return newData;
218            }
219    
220            /**
221             * ?で使用する LineModel を作?します?
222             * こ?クラスは、?ロセスチェインの基点となります?で、新?LineModel を返します?
223             * Exception 以外では、? LineModel オブジェクトを返します?
224             *
225             * @param       rs      ??タベ?スカーソル(リザルトセ?)
226             *
227             * @return      ??タベ?スから取り出して変換した LineModel
228             * @throws RuntimeException カラ?を取得できなかった?合?
229             */
230            private LineModel createLineModel( final ResultSet rs ) {
231                    LineModel model = new LineModel();
232    
233                    try {
234                            ResultSetMetaData metaData      = rs.getMetaData();
235    
236                            int size =  metaData.getColumnCount();
237                            model.init( size );
238    
239                            for(int clm = 0; clm < size; clm++) {
240                                    String name = (metaData.getColumnLabel(clm+1)).toUpperCase(Locale.JAPAN) ;
241                                    model.setName( clm,name );
242                            }
243                    }
244                    catch (SQLException ex) {
245                            String errMsg = "ResultSetMetaData から、カラ?を取得できませんでした?;
246                            throw new RuntimeException( errMsg,ex );
247                    }
248                    return model;
249            }
250    
251            /**
252             * プロセスの処?果のレポ?ト表現を返します?
253             * 処??ログラ?、?力件数、?力件数などの??です?
254             * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
255             * 形式で出してください?
256             *
257             * @return   処?果のレポ??
258             */
259            public String report() {
260                    String report = "[" + getClass().getName() + "]" + CR
261                                    + TAB + "DBID        : " + dbid + CR
262                                    + TAB + "Input Count : " + count ;
263    
264                    return report ;
265            }
266    
267            /**
268             * こ?クラスの使用方法を返します?
269             *
270             * @return      こ?クラスの使用方?
271             */
272            public String usage() {
273                    StringBuilder buf = new StringBuilder();
274    
275                    buf.append( "Process_DBReaderは、データベ?スから読み取った?容を?LineModel に設定後?"       ).append( CR );
276                    buf.append( "下流に渡す?FirstProcess インターフェースの実?ラスです?"                                    ).append( CR );
277                    buf.append( CR );
278                    buf.append( "??タベ?スから読み取った?容より、LineModelを作?し?下?プロセス"                 ).append( CR );
279                    buf.append( "チェインは、チェインして?ため、データは上流から下流へと渡されます?)"             ).append( CR );
280                    buf.append( "に渡します?ここで?できるのは、検索系SQL のみです?"                                          ).append( CR );
281                    buf.append( CR );
282                    buf.append( "??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に"                    ).append( CR );
283                    buf.append( "設定された接?Connection)を使用します?"                                                                               ).append( CR );
284                    buf.append( CR );
285                    buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
286                    buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に"             ).append( CR );
287                    buf.append( "繋げてください?                                                                                                                              ).append( CR );
288                    buf.append( CR );
289                    buf.append( "SQL?は、{@DATE.YMDH}等?シス?変数が使用できます?"                                          ).append( CR );
290                    buf.append( CR ).append( CR );
291    
292                    buf.append( getArgument().usage() ).append( CR );
293    
294                    return buf.toString();
295            }
296    
297            /**
298             * こ?クラスは、main メソ?から実行できません?
299             *
300             * @param       args    コマンド引数配?
301             */
302            public static void main( final String[] args ) {
303                    LogWriter.log( new Process_DBReader().usage() );
304            }
305    }