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.Closer;
020 import org.opengion.fukurou.util.LogWriter;
021 import org.opengion.fukurou.model.Formatter;
022 import org.opengion.fukurou.db.ConnectionFactory;
023
024 import java.util.Map ;
025 import java.util.LinkedHashMap ;
026
027 import java.sql.Connection;
028 import java.sql.PreparedStatement;
029 import java.sql.ParameterMetaData;
030 import java.sql.ResultSet;
031 import java.sql.SQLException;
032
033 /**
034 * Process_DBCountFilter は、データベ?スの存在件数でフィルタリングする
035 * ChainProcess インターフェースの実?ラスです?
036 * 上?プロセスチェインの??タは上流から下流へと渡されます?)から受け取っ?
037 * LineModel を?に、データベ?スの存在チェ?を行い、下流への処?振り?けます?
038 * 具体的には、指定す?SELECT ??、?、?select count(*) from ???』形式にして下さ??
039 * 検索カラ??、??で、そこには数字が入ります?
040 *
041 * ??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に
042 * 設定された接?Connection)を使用します?
043 *
044 * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ??
045 * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に
046 * 繋げてください?
047 *
048 * @og.formSample
049 * Process_DBCountFilter -dbid=DBGE -sql="select count(*) from GEA03"
050 *
051 * [ -dbid=DB接続ID ] ??-dbid=DBGE (? Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規?
052 * [ -sql=検索SQL? ] ??-sql="SELECT COUNT(*) FROM GEA03
053 * WHERE SYSTEM_ID = [SYSTEM_ID]
054 * AND CLM = [CLM]
055 * AND FGJ = '1'"
056 * [ -sqlFile=検索SQLファイル ] ??-sqlFile=select.sql
057 * ?? -sql ?-sqlFile が指定されな??合?、エラーです?
058 * [ -count=スルー条件 ] ??-count=[0|1|2] は、検索値に応じたスルー条件?
059 * 0:?件時にスルー(処?継? つまり?なければ継?
060 * 1:?件時にスルー(処?継? つまり?あれば継?
061 * 2:?件以上ある?合にスルー つまり?キー重?に継?
062 * [ -display=[false/true] ] ?結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
063 * [ -debug=[false/true] ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない])
064 *
065 * @version 4.0
066 * @author Kazuhiko Hasegawa
067 * @since JDK5.0,
068 */
069 public class Process_DBCountFilter extends AbstractProcess implements ChainProcess {
070
071 private Connection connection = null;
072 private PreparedStatement pstmt = null ;
073 private ParameterMetaData pMeta = null; // 5.1.1.0 (2009/11/11) setObject に、Type を渡す?(PostgreSQL対?
074 private boolean useParamMetaData = false; // 5.1.1.0 (2009/11/11) setObject に、Type を渡す?(PostgreSQL対?
075
076 private String dbid = null;
077 private String sql = null;
078 private int cntFlag = -2; // スルー条件 [0|1|2]
079 private boolean display = false; // 表示しな?
080 private boolean debug = false; // 5.7.3.0 (2014/02/07) ????
081
082 private int[] clmNos = null; // ファイルのヘッ??のカラ?号
083 private boolean firstRow = true; // ??の?目
084 private int count = 0;
085
086 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map
087 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map
088
089 static {
090 mustProparty = new LinkedHashMap<String,String>();
091
092 usableProparty = new LinkedHashMap<String,String>();
093 usableProparty.put( "dbid", "Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規? );
094 usableProparty.put( "sql", "カウン?QL?sql or sqlFile ??)" +
095 CR + "? \"SELECT COUNT(*) FROM GEA03 " +
096 CR + "WHERE SYSTEM_ID = [SYSTEM_ID] " +
097 CR + "AND CLM = [CLM] AND FGJ = '1'\"" );
098 usableProparty.put( "sqlFile", "検索SQLファイル(sql or sqlFile ??)? select.sql" );
099 usableProparty.put( "count", "[0|1|2] は、検索値に応じたスルー条件" +
100 CR + " 0:?件時にスルー(処?継? つまり?なければ継? +
101 CR + " 1:?件時にスルー(処?継? つまり?あれば継? +
102 CR + " 2:?件以上ある?合にスルー つまり?キー重?に継? );
103 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? +
104 CR + "(初期値:false:表示しな?" );
105 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? +
106 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ????
107 }
108
109 /**
110 * ?ォルトコンストラクター?
111 * こ?クラスは、動??されます??ォルトコンストラクターで?
112 * super クラスに対して、?な初期化を行っておきます?
113 *
114 */
115 public Process_DBCountFilter() {
116 super( "org.opengion.fukurou.process.Process_DBCountFilter",mustProparty,usableProparty );
117 }
118
119 /**
120 * プロセスの初期化を行います?初めに??、呼び出されます?
121 * 初期処?ファイルオープン??オープン?に使用します?
122 *
123 * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
124 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ?ConnectionFactory経由で取得?(PostgreSQL対?
125 *
126 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク?
127 */
128 public void init( final ParamProcess paramProcess ) {
129 Argument arg = getArgument();
130
131 sql = arg.getFileProparty("sql","sqlFile",true);
132 cntFlag = arg.getProparty("count",cntFlag);
133 display = arg.getProparty("display",display);
134 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ????
135 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ????
136
137 dbid = arg.getProparty("dbid");
138 connection = paramProcess.getConnection( dbid );
139 // useParamMetaData = ApplicationInfo.useParameterMetaData( connection ); // 5.1.2.0 (2010/01/01)
140 useParamMetaData = ConnectionFactory.useParameterMetaData( dbid ); // 5.3.8.0 (2011/08/01)
141 }
142
143 /**
144 * プロセスの終?行います??に??、呼び出されます?
145 * 終???ファイルクローズ??クローズ?に使用します?
146 *
147 * @og.rev 4.0.0.0 (2007/11/27) commit,rollback,remove 処?追?
148 * @og.rev 5.1.2.0 (2010/01/01) pMeta のクリア
149 *
150 * @param isOK ト?タルで、OK?たかど? [true:成功/false:失敗]
151 */
152 public void end( final boolean isOK ) {
153 boolean flag = Closer.stmtClose( pstmt );
154 pstmt = null;
155 pMeta = null; // 5.1.1.0 (2009/11/11)
156
157 ConnectionFactory.remove( connection,dbid );
158
159 if( !flag ) {
160 String errMsg = "ス??トメントをクローズ出来ません?;
161 throw new RuntimeException( errMsg );
162 }
163 }
164
165 /**
166 * 引数の LineModel を??るメソ?です?
167 * 変換処?? LineModel を返します?
168 * 後続??行わな?????タのフィルタリングを行う場?は?
169 * null ??タを返します?つまり?null ??タは、後続??行わな?
170 * フラグの代わりにも使用して?す?
171 * なお?変換処?? LineModel と、オリジナルの LineModel が?
172 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す?
173 * ドキュメントに明記されて???合?、副作用が問題になる?合??
174 * ???とに自?コピ?(クローン)して下さ??
175 *
176 * @og.rev 5.1.2.0 (2010/01/01) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
177 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData setNull 対?PostgreSQL対?
178 * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
179 *
180 * @param data ラインモ? オリジナルのLineModel
181 *
182 * @return 処?換後?LineModel
183 */
184 public LineModel action( final LineModel data ) {
185 LineModel rtnData = data;
186
187 count++ ;
188 try {
189 if( firstRow ) {
190 pstmt = makePrepareStatement( data );
191 if( useParamMetaData ) {
192 pMeta = pstmt.getParameterMetaData();
193 }
194 firstRow = false;
195 if( display ) { println( data.nameLine() ); } // 5.7.3.0 (2014/02/07) ????
196 }
197
198 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対?
199 if( useParamMetaData ) {
200 for( int i=0; i<clmNos.length; i++ ) {
201 int type = pMeta.getParameterType( i+1 );
202 // 5.3.8.0 (2011/08/01) setNull 対?
203 // pstmt.setObject( i+1,data.getValue(clmNos[i]),type );
204 Object val = data.getValue(clmNos[i]);
205 if( val == null || ( val instanceof String && ((String)val).isEmpty() ) ) {
206 pstmt.setNull( i+1, type );
207 }
208 else {
209 pstmt.setObject( i+1, val, type );
210 }
211 }
212 }
213 else {
214 for( int i=0; i<clmNos.length; i++ ) {
215 pstmt.setObject( i+1,data.getValue(clmNos[i]) );
216 }
217 }
218
219 int cnt = -1;
220 ResultSet result = null;
221 try {
222 result = pstmt.executeQuery();
223 if( result.next() ) { // ?行目固?
224 cnt = result.getInt( 1 ); // ?カラ?固?
225 }
226 }
227 finally {
228 Closer.resultClose( result ) ;
229 }
230
231 if( ( cnt > 2 && cntFlag != 2 ) ||
232 ( cnt <= 2 && cnt != cntFlag ) ) {
233 rtnData = null; // 不??
234 }
235 // if( display ) { printKey( count,cnt,data ); }
236 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更
237 }
238 catch (SQLException ex) {
239 // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
240 String errMsg = "SQL を実行できませんでした? + CR
241 + "errMsg=[" + ex.getMessage() + "]" + CR
242 + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
243 + "dbid=[" + dbid + "]" + CR
244 + "sql =[" + sql + "]" + CR
245 + "data=[" + data.dataLine() + "]" + CR ;
246 // String errMsg = "sql=[" + sql + "]" + CR +
247 // "errorCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR ;
248 throw new RuntimeException( errMsg,ex );
249 }
250 return rtnData;
251 }
252
253 /**
254 * ?で使用する PreparedStatement を作?します?
255 * 引数?? SQL また?、LineModel から作?した SQL より構築します?
256 *
257 * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
258 *
259 * @param data ラインモ? 処?象のLineModel
260 *
261 * @return PreparedStatementオブジェク?
262 */
263 private PreparedStatement makePrepareStatement( final LineModel data ) {
264
265 // カラ?号は、makeFormat の処?設定して?す?
266 Formatter format = new Formatter( data );
267 format.setFormat( sql );
268 sql = format.getQueryFormatString();
269 clmNos = format.getClmNos();
270
271 final PreparedStatement ps ;
272 try {
273 ps = connection.prepareStatement( sql );
274 }
275 catch (SQLException ex) {
276 // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します?
277 String errMsg = "PreparedStatement を取得できませんでした? + CR
278 + "errMsg=[" + ex.getMessage() + "]" + CR
279 + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR
280 + "dbid=[" + dbid + "]" + CR
281 + "sql =[" + sql + "]" + CR
282 + "data=[" + data.dataLine() + "]" + CR ;
283 // String errMsg = "PreparedStatement を取得できませんでした? + CR
284 // + "sql=[" + sql + "]" + CR
285 // + "nameLine=[" + data.nameLine() + "]" ;
286 throw new RuntimeException( errMsg,ex );
287 }
288
289 return ps;
290 }
291
292 /**
293 * プロセスの処?果のレポ?ト表現を返します?
294 * 処??ログラ?、?力件数、?力件数などの??です?
295 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ?
296 * 形式で出してください?
297 *
298 * @return 処?果のレポ??
299 */
300 public String report() {
301 String report = "[" + getClass().getName() + "]" + CR
302 + TAB + "DBID : " + dbid + CR
303 + TAB + "Output Count : " + count ;
304
305 return report ;
306 }
307
308 /**
309 * 画面出力用のフォーマットを作?します?
310 *
311 * @og.rev 5.7.3.0 (2014/02/07) 表示方法?変更のため、?
312 *
313 * @param rowNo ??タ読み取り件数
314 * @param cnt 検索結果(の件数)
315 * @param data ラインモ?
316 */
317 // private void printKey( final int rowNo , final int cnt , final LineModel data ) {
318 // StringBuilder buf = new StringBuilder();
319 //
320 // buf.append( "row=[" ).append( rowNo ).append( "] : " );
321 // buf.append( "count=[" ).append( cnt ).append( "] " );
322 // for( int i=0; i < clmNos.length; i++ ) {
323 // if( i == 0 ) { buf.append( "where " ); }
324 // else { buf.append( " and " ); }
325 // buf.append( data.getName( clmNos[i] ) );
326 // buf.append( " = " );
327 // buf.append( data.getValue( clmNos[i] ) );
328 // }
329 //
330 // println( buf.toString() );
331 // }
332
333 /**
334 * こ?クラスの使用方法を返します?
335 *
336 * @return こ?クラスの使用方?
337 */
338 public String usage() {
339 StringBuilder buf = new StringBuilder();
340
341 buf.append( "Process_DBCountFilter は、データベ?スの存在件数でフィルタリングする" ).append( CR );
342 buf.append( "ChainProcess インターフェースの実?ラスです?" ).append( CR );
343 buf.append( "上?プロセスチェインの??タは上流から下流へと渡されます?)から" ).append( CR );
344 buf.append( "受け取っ?LineModel を?に、データベ?スの存在チェ?を行い? ).append( CR );
345 buf.append( "下流への処?振り?けます?" ).append( CR );
346 buf.append( "存在チェ?で?す?SELECT ??、?、?select count(*) from ???? ).append( CR );
347 buf.append( "形式にして下さ??検索カラ??、??で、そこには数字が入ります?" ).append( CR );
348 buf.append( CR );
349 buf.append( "??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に" ).append( CR );
350 buf.append( "設定された接?Connection)を使用します?" ).append( CR );
351 buf.append( CR );
352 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR );
353 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR );
354 buf.append( "繋げてください? ).append( CR );
355 buf.append( CR ).append( CR );
356 buf.append( getArgument().usage() ).append( CR );
357
358 return buf.toString();
359 }
360
361 /**
362 * こ?クラスは、main メソ?から実行できません?
363 *
364 * @param args コマンド引数配?
365 */
366 public static void main( final String[] args ) {
367 LogWriter.log( new Process_DBCountFilter().usage() );
368 }
369 }