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