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    }